Hi guys,

I have one simple logical question that I seem not to figure it out, sadly...

We have a list of objects and I loop trough them, list of products.
We need to create anchor maps for each category, so I did a comparison with temp variables to check the previous and current element value.

How can I display only the first occurence of a series of values for each category ?

Desired result:

Category 1
- product 1
- product 2
- product 3
Category 2
- product 1
- product 2
- product 3

    $previous = '';
    if(!empty($promotii)) {
        foreach($promotii as $promotie) {
            $previous = $promotie->Marca;
        }
        $previous = $promotie->Marca;
     }

Dani AI

Generated

Two simple, reliable ways solve this: keep a “previous” marker while iterating a sorted list, or build a grouped array first and then render. The marker method is fine for a pre-sorted result (and is what ended up using), but it’s easy to make a tiny logic error that breaks the grouping — for example, accidentally comparing instead of assigning (a subtle problem in ' early sample). Grouping first separates logic from presentation and is less error-prone.

A compact grouping pattern (works whether categories are contiguous or mixed):

if (empty($promotii)) { return; }

$byMarca = [];
foreach ($promotii as $promo) {
    $byMarca[$promo->Marca][] = $promo;
}

echo '<table class="table table-condensed"><tbody>';
foreach ($byMarca as $marca => $items) {
    echo '<tr><td>' . htmlspecialchars($marca, ENT_QUOTES, 'UTF-8') . '</td></tr>';
    foreach ($items as $it) {
        echo '<tr><td>' . htmlspecialchars($it->Product, ENT_QUOTES, 'UTF-8') . '</td></tr>';
    }
}
echo '</tbody></table>';

Notes and troubleshooting tips:

  • To preserve the order of first appearance, build the grouped array in one pass as above. If you want alphabetical grouping, sort $promotii first (e.g., usort) then group.
  • Always escape output (htmlspecialchars) to avoid XSS.
  • For very large datasets, push the grouping/sorting into SQL (ORDER BY Marca) to reduce memory and processing in PHP.
  • If you stick with the “previous” marker approach, set the marker immediately after printing the header and make sure you emit any necessary closing tags when the category changes and after the loop ends.

These approaches make the intent clearer and reduce edge-case bugs compared with in-loop ad-hoc checks.

Recommended Answers

All 2 Replies

Something like this:

$previous = '';
foreach($promotii as $promotie) 
{
    if ($previous != $promotie->Marca)
    {
        if (!empty($previous))
        {
            echo '</ul>';
        }

        $previous != $promotie->Marca;

        echo $promotie->Marca . '<ul>';
    }

    echo "<li>$promotie->Product</li>";
}

if (!empty($previous))
{
    echo '</ul>';
}

Thanks pritaeas for the heads up, it was a great start :)
This is my final implementation and it works great.

        echo '<table width="600" cellpadding="0" cellspacing="0" border="0" class="table table-condensed">';    
        echo '<tbody>';        
        $previous = '';
        foreach($promotii as $promotie) {            
            if ($previous != $promotie->Marca) {
                if (!empty($previous)) {
                } else {
                    $previous = $promotie->Marca;
                }

                echo '<tr>';
                    echo '<td>';
                        echo $promotie->Marca;
                    echo '</td>';
                echo '</tr>';                  
            }

            echo '<tr>'; // start product stuff
            echo '</tr>'; // end of product stuff

            $previous = $promotie->Marca;
        }
        echo '</tbody>';
        echo '</table>';      
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.