views:

504

answers:

4

I'm using following peace of code to output an array:

echo "======output without array_unique=====";
var_dump($selected);
echo "=====output with array_unique=====";
var_dump(array_unique($selected));die;

And the output is:

======output without array_unique=====

array
  0 => 
    array
      'uri' => string 'http://localhost/conferences/tags/0caf4c990e0a385156b33fee58e7e3fb' (length=63)
      'tag' => string '1' (length=1)
      'weight' => float 4
      'selected' => string 'select' (length=6)
  1 => 
    array
      'uri' => string 'http://localhost/conferences/tags/0caf4c990e0a385156b33fee58e7e3fb' (length=63)
      'tag' => string '1' (length=1)
      'weight' => float 4
      'selected' => string 'select' (length=6)
  2 => 
    array
      'uri' => string 'http://localhost/conferences/tags/ffc709d5131f752df8aae22d7da4240f' (length=63)
      'tag' => string '2' (length=1)
      'weight' => float 4
      'selected' => string '' (length=0)
  3 => 
    array
      'uri' => string 'http://localhost/conferences/tags/035c60c7f090412cc905cee008fbeba8' (length=63)
      'tag' => string '3' (length=1)
      'weight' => float 0
      'selected' => string '' (length=0)
  4 => 
    array
      'uri' => string 'http://localhost/conferences/tags/4137dbc16ef1a2079eb6cacb62dd8521' (length=63)
      'tag' => string '4' (length=1)
      'weight' => float 0
      'selected' => string '' (length=0)

=====output with array_unique=====

array
  0 => 
    array
      'uri' => string 'http://localhost/conferences/tags/0caf4c990e0a385156b33fee58e7e3fb' (length=63)
      'tag' => string '1' (length=1)
      'weight' => float 4
      'selected' => string 'select' (length=6)

Can someone explain me, why i get array with only one element from the array_unique?

+6  A: 

The array elements are cast to strings for comparison - here's the relevant snippet from the manual page for array_unique

Note: Two elements are considered equal if and only if (string) $elem1 === (string) $elem2. In words: when the string representation is the same. The first element will be used.

Once your array elements are cast to strings, they simply have the value "Array", which of course makes every element look the same, and you wind up with just the first element.

Here's one way you could remove duplicates from an array like yours

$seen=array();
foreach($myarray as $key=>$val)
{
    if (isset($seen[$val['uri']])
    {
         //remove dupe
         unset($myarray[$key]);
    }
    else
    {
         //remember this
         $seen[$val['uri']]=$key;
    }
}
unset($seen); //don't need this any more
Paul Dixon
nice pick up there. Just to elaborate: any array cast to a string is `"array"`, so it's comparing `"array" == "array"`
nickf
In php 5.2.6 at least, it is Array, try echo (string)array("foo");
Paul Dixon
@Paul Dixon: great! thank you ver much for the answer and for the example!
cupakob
+2  A: 

array_unique removes duplicates by comparing the string value of the elements. The string value of an array is always "Array", independent of the contents of the array.

This means that all the elements of your array have the string value "Array", and are therefore considered duplicates, and are removed except for the first one.

You should write your own array_unique function that works by comparing the 'uri' of the elements.

michaelk
+1  A: 

I imagine that since $selected is a multi-dimensional array, $selected[0] is the same as $selected[1], an array.

As far as I know, array_unique tests (string) $value1 === (string) $value2, so you get 'Array' == 'Array'.

You haven't really explained what makes an element 'unique' (the URI?). To compare whole structures, you may want to try looping through $selected, serializing the values (using serialize()) and then calling array_unique on those values. Then, call unserialize to return the array to normal.

<?php

function multi_array_unique($arr) {
    foreach ($arr as &$elm) {
        $elm = serialize($elm);
    }

    $arr = array_unique($arr);

    foreach ($arr as &$elm) {
        $elm = unserialize($elm);
    }

    return $arr;
}

?>

It isn't the most efficient solution, but I would benchmark first, before I worry about that.

See: http://codepad.org/6cs5b0sm

Nick Presta
A: 

If the array elements are already sorted, you can find the unique values with this:

$unique = array();
$n = count($array);
if ($n < 2) {
    $unique = $array;
} else {
    for ($i=0; $i<$n-1; ++$i) {
        $unique[] = $array[$i];
        if ($array[$i] === $array[$i+1]) {
            ++$i;
        }
    }
    if ($i < $n && $array[$n-2] !== $array[$n-1]) {
        $unique[] = $array[$n-1];
    }
}
Gumbo