Higeath Higeath - 4 months ago 11
PHP Question

Merging values of nested array

As the title says I get array looking something like this:

array (size=376)
0 =>
array (size=3)
'source' => int 0
'target' => int 47
'officers' =>
array (size=1)
0 => string 'PARKER, Thomas, Sir' (length=19)
1 =>
array (size=3)
'source' => int 0
'target' => int 104
'officers' =>
array (size=1)
0 => string 'STEVENS, Anne' (length=13)
2 =>
array (size=3)
'source' => int 0
'target' => int 187
'officers' =>
array (size=1)
0 => string 'PARKER, Thomas, Sir' (length=19)
3 =>
array (size=3)
'source' => int 0
'target' => int 229
'officers' =>
array (size=1)
0 => string 'GROTE, Byron' (length=12)
4 =>
array (size=3)
'source' => int 0
'target' => int 244
'officers' =>
array (size=1)
0 => string 'GROTE, Byron' (length=12)
5 =>
array (size=3)
'source' => int 1
'target' => int 60
'officers' =>
array (size=1)
0 => string 'BASON, John' (length=11)
6 =>
array (size=3)
'source' => int 1
'target' => int 92
'officers' =>
array (size=1)
0 => string 'HAUSER, Wolfhart, Dr' (length=20)


If source and target are the same I want to create 1 value in this array for example

Insteed of this:

5 =>
array (size=3)
'source' => int 1
'target' => int 92
'officers' =>
array (size=1)
0 => string 'BASON, John' (length=11)
6 =>
array (size=3)
'source' => int 1
'target' => int 92
'officers' =>
array (size=1)
0 => string 'HAUSER, Wolfhart, Dr' (length=20)


I would want to get

5 =>
array (size=3)
'source' => int 1
'target' => int 92
'officers' =>
array (size=1)
0 => string 'BASON, John' (length=11)
1 => string 'HAUSER, Wolfhart, Dr' (length=20)


My idea to achieve this:

for ($i = 0; $i < count($edges); $i++) {
for ($j = $i + 1; $j < count($edges); $j++) {
if($edges[$i]['source']==$edges[$j]['source']&&$edges[$i]['target']==$edges[$j]['target']){
foreach( $edges[$j]['officers'] as $officer){
array_push($edges[$i]['officers'], $officer);
}
array_splice($edges, $j,1);
}

}
}


It seems to be merging but only 2 values and it isn't deleting old values so:

I got something like :

66 =>
array (size=3)
'source' => int 24
'target' => int 103
'officers' =>
array (size=2)
0 => string 'GILAURI, Irakli' (length=15)
1 => string 'JANIN, Neil' (length=11)
67 =>
array (size=3)
'source' => int 24
'target' => int 103
'officers' =>
array (size=1)
0 => string 'MORRISON, David' (length=15)


So it merget Gilauri and Janin but didn't add Morrison, David to officers array and also Gilauri, Irakli and Janin, Neil have separate row in this array which shouldn't be added.

Answer

Note that array_splice rekeys the array each time it is executed. From the documentation:

Note that numeric keys in input are not preserved.

I.e. array_splice($array, 1, 1) on $array = [0 => 1, 1 => 2, 2 => 3] will result in [0 => 1, 1 => 3].

Thus when you are iterating with a for loop, your index will point one entry further than before for each removed array element.

To remove by index without rekeying, use unset($edges[$j]) instead of the array_splice().

Alternatively use a foreach loop (by reference to operate on the actual loop and not on a copy):

foreach ($edges as $i => &$edge) {
    for ($j = $i + 1; $j < count($edges); $j++) {
        if ($edge['source'] == $edges[$j]['source'] && $edge['target'] == $edges[$j]['target']) {
            foreach ($edges[$j]['officers'] as $officer) {
                array_push($edge['officers'], $officer);
            }
            array_splice($edges, $j, 1);
        }
    }
}

But I recommend the unset() alternative as it is much faster (array_splice always recreates the array completely).

Comments