Jump to content

Remove duplicates in a foreach loop (but count them)


Reid Bramblett
 Share

Recommended Posts

I am trying to create a list of all the "interest" tags associated with a set of pages. A page can have any number of tags, which are stored in an "interests" field.

I can generate a list of all these interests from the requisite pages in a foreach loop, but of course I get all instances of all interests—so if a particular interest tag is on four of the pages, it shows up four times.

My code:

<ul><?php
$kids=$pages->find("template=poi, has_parent=$page");
   foreach ($kids as $k) {
      $ints=$k->interests;
      $ints->unique();
         foreach ($ints as $i) {
            "<li><a href='interest/$i->name'>$i->title</a></li>";
         }
   }
?>
</ul>

(I left the "$ints->unique()" line in there—though it is not actually doing anything—because I was convinced it would work. In fact, I played around with jamming "unique()" into more than a dozen places and variations, but perhaps I am misunderstanding that function; I am still a bit shaky on WireArray vs. PageArray.)  

My most pressing question is: How can I limit the list of results to just one instance of each interest tag.

The irony is, I do actually care about how many times an interest tag is used, because on my wish list for this snippet of code is the ability to count that total number, use it to sort the list of interests (by frequency of occurrence), and then also pop it into the list beside each interest title, so the end result would look like this:

  • Interest 1 (20)
  • Interest 2 (16)
  • Interest 3 (12)
  • Interest 4 (8)

... only, you know, with better CSS styling.

I've trawled the forum, but none of the solutions to similar situations I found here worked for me, and I poked around the sample blog profile (which has something a bit similar) for inspiration, but to no avail. Any ideas? Thanks.

Link to comment
Share on other sites

You could filter them out in a temporary array...e.g.

//example code
$interests = $pages->find('template=poi, interests!=""');

//method 1
foreach ($interests as $int) {	
	foreach ($int->interests as $p) {//interests is a multi page field; PW returns them as objects		
		$array1[$p->id] =  $p->title;//overwrite duplicate ids in the array key
	}
}

//method 2
foreach ($interests as $int) {	
	foreach ($int->interests as $p) {
		if(in_array($p->id, $array2)) continue;//if we already have that id, skip it
		$array2[] =  $p->id;	
	}
}

//testing
echo '<pre>';
print_r($array1);
echo '</pre>';

echo count($array1);

echo '<hr>';
echo '<pre>';
print_r($array2);
echo '</pre>';

echo count($array2);

Above are just examples. You could even store objects in the arrays, or create a temporary WireArray and store them in there.

WireArray and PageArray docs: http://processwire.com/api/arrays/

Btw, the above code will not do the counting you want. That's easily doable as well...

Edit:

Reading your question again, this is probably not what you want...Oh well, code stays though.. :-)

Edited by kongondo
  • Like 4
Link to comment
Share on other sites

you have some options...

<?php
// version using PageArray();

$kids = $pages->find("template=poi, has_parent=$page");
$interests = new PageArray();
foreach ($kids as $k)  $interests->import($k->interests);

echo '<ul>';
foreach ($interests as $i) {
    echo "<li><a href='interest/$i->name'>$i->title</a></li>";
}
echo '</ul>';

// or find all interests, cycle through but ignore those that don't apply to this page

$interests = $pages->find("template=interest");

echo '<ul>';
foreach ($interests as $i) {
  if(!count($pages->find("template=poi, has_parent=$page, interests=$i"))) continue;
  echo "<li><a href='interest/$i->name'>$i->title</a></li>";
}
echo '</ul>';

?>

wow, 3 replies!

Edited by Macrura
  • Like 4
Link to comment
Share on other sites

Thanks for all the speedy replies!

Macrura, your first example ends up spewing out even more duplicate hits. Haven't tried troubleshooting that method much yet because I like the backwards logic of !count, but when I try that it throws an error:

Parse error: syntax error, unexpected 'continue' (T_CONTINUE) in /Applications/MAMP/htdocs/test-pw/site/templates/_main.php on line 339

Link to comment
Share on other sites

Thanks for all the speedy replies!

Macrura, your first example ends up spewing out even more duplicate hits. Haven't tried troubleshooting that method much yet because I like the backwards logic of !count, but when I try that it throws an error:

Parse error: syntax error, unexpected 'continue' (T_CONTINUE) in /Applications/MAMP/htdocs/test-pw/site/templates/_main.php on line 339

ok i fixed the code for the 2nd one adding the missing close )

however the first example should work, there can't be duplicate pages in the PageArray(), so you must be doing something funky if you are getting the same 'interest' tag. Are you positive you don't have duplicates in your system - are the interests all stored under the same parent? You should check;

if you do have duplicate interest titles in your system PW can't remove the duplicates from the array because it is keyed to the page ID.

you could sort the array by title and then check to see if the previous item has the same title and then skip it, that's an easy way to exclude duplicates.

Link to comment
Share on other sites

OK, I hereby promise to be better about posting "it don't work!" replies at the end of the day when I'm too tired and rushed to take the debug time to notice a simple thing like a missing close parentheses.

(Even as a PHP newbie I should have known this, as I often try to solve such problems by sticking semicolons and/or right curly braces at the ends of random lines of code until the thrown error page goes away, figuring I must have missed one somewhere.)

The second code works perfectly now. Thanks all.

Link to comment
Share on other sites

Incidentally, @Macrura, your first suggestion is also now working. No idea why it failed yesterday, but the PageArray version is humming along smoothly now. (Each "interest" is, indeed, a unique page stored under an Interests page.)

I will definitely use the PageArray version since it will allow me superior sorting options (er, once I figure out how to fiddle with arrays and do the counting part; as I said: PHP noob). Thanks again.

  • Like 1
Link to comment
Share on other sites

you mean counting like this?

$kids = $pages->find("template=poi, has_parent=$page");
$interests = new PageArray();
foreach ($kids as $k)  $interests->import($k->interests);

$iTotal = count($interests);
foreach ($interests as $i) $i->useCount = count($pages->find("interests=$i"));

echo "<h3>Interests ($iTotal)</h3>";

echo '<ul>';
foreach ($interests->sort("-useCount") as $i) {
    echo "<li><a href='interest/$i->name'>$i->title</a> ($i->useCount)</li>";
}
echo '</ul>';
  • Like 8
Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...