Page 1 of 1

extract unique values in nested array

Posted: Wed Jun 22, 2011 8:02 pm
by doughemi
I have a nested array extracted from a Filemaker database using the Filemaker PHP API. Essentially it looks like this

Code: Select all

[1]=>
     array(
          "id"=>"12345",
          "name"=>"name1",
          ...
     ),
[2]=>
     array(
          "id"=>"23456",
          "name"=>"name2",
          ...
     ),
[3]=>
     array(
          "id"=>"12345",
          "name"=>"name1",
          ...
     ),
)

I'd like to create an array which contains only the records containing unique values of "id" (e.g. [1] and [2] in the above example. How could I do this?

Re: extract unique values in nested array

Posted: Wed Jun 22, 2011 8:15 pm
by Jade

Code: Select all

$i = 0;

//loop through your existing array and pull out all the ID values
foreach ($array as $key => $value)
{
     if ($key == "id")
           $newarray[$i++] = $value;
}

//now make sure the ID values are unique
$newarray = array_unique($newarray);

Re: extract unique values in nested array

Posted: Wed Jun 22, 2011 9:25 pm
by doughemi
Thanks for the quick reply, Jade, but it didn't work.

Code: Select all

<?php 
$records = array (
	array
	(
          "id"=>"12345",
          "name"=>"name1",
//          ...
     ),

     array(
          "id"=>"23456",
          "name"=>"name2",
//          ...
     ),

     array(
          "id"=>"12345",
          "name"=>"name1",
//          ...
     )
);
echo '<pre>';

print_r($records);


//loop through your existing array and pull out all the ID values
foreach ($records as $key => $value)
{
     if ($key == "id")
           $newarray[$i++] = $value;
}

//now make sure the ID values are unique
//$newarray = array_unique($newarray);
echo '<br>-----this is $newarray:<br>';
print_r($newarray);
echo '</pre>';

?>

generated this:
Array
(
[0] => Array
(
[id] => 12345
[name] => name1
)

[1] => Array
(
[id] => 23456
[name] => name2
)

[2] => Array
(
[id] => 12345
[name] => name1
)

)

-----this is $newarray:
Array
(
[] => Array
(
[id] => 12345
[name] => name1
)

)
without even getting to the array_unique directive. Shouldn't it have duplicated the original data?

--Doug

Re: extract unique values in nested array

Posted: Wed Jun 22, 2011 10:42 pm
by Jade
Yes it should have, check to make sure you're doing $i++ it looks like it's overwriting the array index each time it goes through the loop.

Re: extract unique values in nested array

Posted: Wed Jun 22, 2011 11:22 pm
by doughemi
I put in an "echo $i" and it does index up to 2 with three records, as expected. To me it appears that the $Key=>$value statement is looking at one array level higher than the id key, but perhaps I just don't understand how arrays work. Does the foreach drill down to each nesting level of the array to find keys? Or are we missing syntax to tell it, "hey, key "id" is in the second level of array nesting"?

--Doug

Re: extract unique values in nested array

Posted: Wed Jun 22, 2011 11:35 pm
by McInfo
Jade, in your foreach loop, $key is in the set {0, 1, 2} (or {1, 2, 3} depending on which post you look at). You must have misread the question. The input is an array of arrays. There ends up being one item in $newarray because integer 0 equals string 'id'.

Doug, here are some solutions I cooked up.

The first is the simplest, but does not preserve the original keys. Instead, the ids become the keys. Because keys of an array are unique, this is a simple way to ensure the array contains no duplicate records. Existing records just get overwritten with (hopefully) identical data.

Code: Select all

$uniqueRecords = array();
foreach ($records as $record) {
    $uniqueRecords[$record['id']] = $record;
}
You can use array_values() to make the keys sequential and start at zero again, but that still won't restore the original keys.

If you want to maintain the original keys, you can use array_filter(). This example uses an anonymous (lambda/closure) function. It uses a static variable (maintained between function calls) to collect ids as they are discovered and compares the current id with the array of known ids to determine if the current record is a duplicate.

Code: Select all

$uniqueRecords = array_filter($records, function($record){
    static $ids = array();
    $isUnique = !in_array($record['id'], $ids);
    if ($isUnique) {
        $ids[] = $record['id'];
    }
    return $isUnique;
});
Here is a variant of the same, except that the ids are stored in the keys of the $ids array. I expect it to be more efficient (though I haven't tested it).

Code: Select all

$uniqueRecords = array_filter($records, function($record){
    static $ids = array();
    $isUnique = !isset($ids[$record['id']]);
    if ($isUnique) {
        $ids[$record['id']] = true;
    }
    return $isUnique;
});
If you like code that is clever but difficult to read, this example does the same with less code. It relies on short-circuit evaluation of the && operator.

Code: Select all

$uniqueRecords = array_filter($records, function($record){
    static $ids = array();
    return !isset($ids[$record['id']]) && $ids[$record['id']] = true;
});

Re: extract unique values in nested array

Posted: Thu Jun 23, 2011 8:03 am
by doughemi
Thanks, McInfo. There is no need in this application to preserve keys, so your first example works beautifully for me. I am hanging on to your other examples for future reference.

--Doug