I have a loop that builds an array of associative arrays that looks like this:
array(
'foo' => '',
'bar' => '',
'thingys' => array()
)
on each iteration of the loop, I want to search through the array for an associate array that's 'foo
' and 'bar
' properties match those of the current associate array. If it exists I want to append the thingys property of the current associative array to the match. Otherwise append the entire thing.
I know how to do this with for loops, but I'm wondering if there is a simpler way to do this with an array function. I'm on php 5.3.
Example
<?php
$arr = array(
array(
'foo' => 1,
'bar' => 2,
'thing' => 'apple'
),
array(
'foo' => 1,
'bar' => 2,
'thing' => 'orange'
),
array(
'foo' => 2,
'bar' => 2,
'thing' => 'apple'
),
);
$newArr = array();
for ($i=0; $i < count($arr); $i++) {
$matchFound = false;
for ($j=0; $j < count($newArr); $j++) {
if ($arr[$i]['foo'] === $newArr[$j]['foo'] && $arr[$i]['bar'] === $newArr[$j]['bar']) {
array_push($newArr[$j]['thing'], $arr[$i]['things']);
$matchFound = true;
break;
}
}
if (!$matchFound) {
array_push($newArr,
array(
'foo' => $arr[$i]['foo'],
'bar' => $arr[$i]['bar'],
'things' => array($arr[$i]['thing'])
)
);
}
}
/*Output
$newArr = array(
array(
'foo' => 1,
'bar' => 2,
'things' => array('orange', 'apple')
),
array(
'foo' => 2,
'bar' => 2,
'things' => array('apple')
),
)
*/
?>
I don't know if it is possible through a built-in function, but I think no. Something can be implemented through array_map
, but anyway you have to perform a double loop.
I propose you a one-loop solution using a temporary array ($keys
) as index of already created $newArr
items, based on foo
and bar
; elements of original array are processed through a foreach
loop, and if a $keys
element with first key as foo
value and second key as bar
value exists, then the current thing
value is added to the returned key index of $newArr
, otherwise a new $newArray
element is created.
$newArr = $keys = array();
foreach( $arr as $row )
{
if( isset( $keys[$row['foo']][$row['bar']] ) )
{ $newArr[$keys[$row['foo']][$row['bar']]]['thing'][] = $row['thing']; }
else
{
$keys[$row['foo']][$row['bar']] = array_push( $newArr, $row )-1;
$newArr[$keys[$row['foo']][$row['bar']]]['thing'] = array( $row['thing'] );
}
}
unset( $keys );
This is the same solution above, using array_map
instead of foreach
loop. Note that also your original code can be converted in this way.
$newArr = $keys = array();
function filterArr( $row )
{
global $newArr, $keys;
if( isset( $keys[$row['foo']][$row['bar']] ) )
{ $newArr[$keys[$row['foo']][$row['bar']]]['thing'][] = $row['thing']; }
else
{
$keys[$row['foo']][$row['bar']] = array_push( $newArr, $row )-1;
$newArr[$keys[$row['foo']][$row['bar']]]['thing'] = array( $row['thing'] );
}
}
array_map( 'filterArr', $arr );