Jump to content
NooseLadder

How to get unique field values from a nested foreach

Recommended Posts

Hi,

$categories = $page->children; 
   foreach ($categories as $category) {
     $categoryNames = $category->categories;
        foreach ($categoryNames as $categoryName) {
        echo $categoryName->title."<br />";
        }
    }

This code gives output:

apple
orange
pear
banana
grape
kiwi
blackberry
passion
fig
apple
orange
pear
banana

I would like to only output unique values. I want to create only unique category links on the page regardless of how many child pages have duplicate categories. Can anyone point me in the right direction?

Share this post


Link to post
Share on other sites

$categories = $categories->unique();

  • Like 4

Share this post


Link to post
Share on other sites

$categories are already unique in the page tree. It's the $categoryName that I want unique. I have tried

$categories = $page->children; 
foreach ($categories as $category) {
$categoryNames = $category->categories;

$categoryNames = $categoryNames->unique();

foreach ($categoryNames as $categoryName) {
echo $categoryName->title."<br />";
}
}

And this

$categories = $page->children; 
foreach ($categories as $category) {
$categoryNames = $category->categories;
foreach ($categoryNames as $categoryName) {

$categoryName = $categoryName->unique();

echo $categoryName->title."<br />";
}
}

But they don't work.

This is the page tree:

The field categories is a multi page select.

Category List (where I want to list unique categories)

       Cat1 (has field categories containing 1 categories = fig)

       Cat2 (has field categories containing 4 categories = apple, orange, pear, banana)

       Cat3 (has field categories containing 8 categories = apple, orange, pear, banana, grape, kiwi, blackberry, passion)

Share this post


Link to post
Share on other sites

How about this (untested)...

$categories = $page->children;

/**
 * This will hold unique values from the possible repeats in your page tree...
 */
$uniques = array();

/**
 * Iterate as you did before but only keep one copy of each category you visit.
 */
foreach ($categories as $category) {
    $categoryNames = $category->categories;
    foreach ($categoryNames as $categoryName) {
        $uniques[$categoryName->id] = $categoryName->title;
    }
}

/**
 * Now do what you want with the uniques. They are indexed by page id.
 */
foreach ($uniques as $id => $title) {
    echo $title, "<br />\n";
}

...?

  • Like 4

Share this post


Link to post
Share on other sites

Can someone explain to me how to use $a->unique();? 

<?php foreach($pages->find("template=item, editorial!='', sort=editorial") as $item) {
 echo $item->editorial;
} ?>

Retrieves a list of publishers ("editorial" field) from a template called "item", but with duplicates:

  1. Abada
  2. Abada
  3. Abada
  4. Academy of Mathematics and Systems Science
  5. Chinese Academy of Sciences
  6. Actar
  7. Actar
  8. etc...

How can I remove the duplicates from this simple loop?

Share this post


Link to post
Share on other sites

As I understand it, you have different items the same editorial (as a text field), and you want to get an array with unique editorils, right? If so, here is the code to get this:

$editorials = array();
$lastEditorial = null;
foreach ($pages->find("template=item, editorial!='', sort=editorial") as $item) {
  if ($item->editorial !== $lastEditorial) $editorials[] = $item->editorial;
  $lastEditorial = $item->editorial;
}

$a->unique() filters elements using the PHP array_unique function, which compares elements according to their string representation. Since the result of $pages->find() returns a PageArray containing Page objects, and since the string representation of a Page object is its id, $pages->find(...)->unique will return unique pages, without considering the editorial field (two different pages with the same editorial will be different, since they will have different ids). That's why $a->unique isn't usable in your case.

  • Like 4

Share this post


Link to post
Share on other sites

Thanks ESRCH for your explanation. I understand now why $a->unique() isn't working. However, I don't understand your code, especially the $lastEditorial variable. And I don't know how to echo it either... 

But you guessed what I wanted to achieve: I have a list of books where various editors typed in publishers manually in a text field, instead of pulling them from a predefined list. Hence my issue with the duplicates: I want a "clean" array with unique publishers.

Share this post


Link to post
Share on other sites

The code from my previous post generates a simple array of editor names, over which you can loop, for example like this:

// $editorials is the array from the code above
foreach ($editorials as $editorial) {
  echo $editorial;
}

The $lastEditorial variable is simply used to avoid duplicates: In the code of the previous post, each iteration first compares the editor ($item->editorial) with the value it had for the previous iteration ($lastEditorial), and if it is not the same, it include it in the new array ($editorials[] = $item->editorial). Then at the end of the loop, the $lastEditorial is updated to have the new value. So using the data that you gave, the iterations go like this:

  1. "Abada" !== "", so add "Abada" to the $editorials array. Set $lastEditorial to "Abada"
  2. "Abada" === "Abada", so don't add the new "Abada" to the loop. Set $lastEditorial to "Abada"
  3. "Abada" === "Abada", so don't add the new "Abada" to the loop. Set $lastEditorial to "Abada"
  4. "Academy of Mathematics" !== "Abada", so add "Academy of Mathematics to the $editorials array. Set $lastEditorial to "Academy of Mathematics"
  5. "Chinese Academy" !== "Academy of Mathematics", so add "Chinese Academy..." to the $editorials array. Set $lastEditorial to "Chinese Academy..."
  6. etc.

The result of this all is to have an array of unique editors.

But if you really just want to echo the editors in place, you can shorten your code to one loop (I also reduced the number of variable assignments):

$editorials = array();
$lastEditorial = "";
foreach($pages->find("template=item, editorial!='', sort=editorial" as $item) {
  if ($item->editorial !== $lastEditorial) {
    echo $item->editorial;
    $lastEditorial = $item->editorial;
  }
}
  • Like 2

Share this post


Link to post
Share on other sites

It should be added, that this only works as long as the PageArray for the foreach is sorted by editorial, otherwise it would be needed to search the whole $editorials array for duplicates and not only the last item. 

  • Like 1

Share this post


Link to post
Share on other sites

ESRCH, you're such a great teacher. I've understood it perfectly. Very smart solution. I love this forum, I always learn something new. Now I have to up my PHP game to be able to return the favor and contribute more.  

  • Like 3

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...