1

I want to consolidate an associative array of indexed arrays by merging rows which have an associative key that is in another row's values.

Consider this sample input:

$array = [
    44259 => [50007, 50009, 46372],
    50007 => [50008],
    50009 => [50010],
    66666 => ['no', 'other', 'links'],
    46372 => [46418, 46419, 46421],
    46421 => [146880]
];

Because the values in the 44259-keyed row (50007, 50009, and 46372) exist as keys in the original array, all of the values from those values should be pushed into the 44259-keyed row.

Continuing the same logic, after the 46372-keyed rows have been added to 44259-keyed row, now the 46421-keyed row values should be pushed into the growing 44259-keyed row.

Desired result:

$array = [
    44259 => [
        50007,  // original
        50009,  // original
        46372,  // original
        50008,  // from 50007
        50010,  // from 50009
        50018,  // from 46372
        46419,  // from 46372
        46421,  // from 46372
        146880, // from 46372 -> 46421
    66666 => [
        'no',
        'other',
        'links'
    ]
];

You see, this is somewhat of a recursive task.

I tried this already:

foreach ($array as $cid => $pid) {
    foreach ($pid as $pip) {
        if (isset($array[$pipp])) {
            foreach ($array[$pipp] as $pip) {
                $array[$cid][] = $pip;
                unset($array[$pipp]);
            }
        }
    }
}

But it's not properly collecting the 46372 row's data for the 44259 row.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Smiley
  • 38
  • 5
  • I'm not sure that this is a good [mcve]. There are answers here which "brute force" push all values into the result array. They are not obeying your described logic, bit their result is identical because of the sample data. Perhaps adjust your sample data in a way which will better identify correct and incorrect answers. I mean, [`var_export([key($array) => array_merge_recursive(...$array)]);`](https://3v4l.org/W3V8r) works, but only by happenstance. (Your desired output is missing an element too.) – mickmackusa Sep 23 '22 at 23:46

6 Answers6

1

You coukd try just merging

$result =array_merge($array[44259],$array[50007] ,$array[50009] ,
                 $array[46372], $array[46421] );
ScaisEdge
  • 131,976
  • 10
  • 91
  • 107
  • This hardcoded solution is surely not going to be helpful in the asker's project (or anyone else's), right? Was this an honest answer? – mickmackusa Sep 24 '22 at 00:48
1

You could get the first key using array_keys() and reset(). Then you could add values of all array to this key:

$array = [];

$array[44259] = [50007, 50009, 46372];
$array[50007] = [50008];
$array[50009] = [50010];
$array[46372] = [46418, 46419, 46421];
$array[46421] = [146880];

$out = [];
$keys = array_keys($array);
$first_key = reset($keys); // $first_key = 44259
foreach ($array as $k => $items) {
  foreach ($items as $val) {
    $out[$first_key][] = $val;
  }
}
print_r($out);

Outputs:

Array
(
    [44259] => Array
        (
            [0] => 50007
            [1] => 50009
            [2] => 46372
            [3] => 50008
            [4] => 50010
            [5] => 46418
            [6] => 46419
            [7] => 46421
            [8] => 146880
        )

)
Syscall
  • 19,327
  • 10
  • 37
  • 52
  • This answer does not obey the asker's requirement to only push values into the result when the respective row key exists in the result array. https://3v4l.org/p2Yls – mickmackusa Sep 24 '22 at 00:49
1
$res = array();
$res[44259] = array();
foreach($array as $pid)
    $res[44259] = array_merge($res[44259], $pid);
print_r($res);
?>

Ouput

Array
(
    [44259] => Array
        (
            [0] => 50007
            [1] => 50009
            [2] => 46372
            [3] => 50008
            [4] => 50010
            [5] => 46418
            [6] => 46419
            [7] => 46421
            [8] => 146880
        )
)
Javier S
  • 379
  • 3
  • 13
  • This answer does not obey the asker's requirement to only push values into the result when the respective row key exists in the result array. https://3v4l.org/plal9 – mickmackusa Sep 24 '22 at 00:51
0

This is probably one way of doing it. Create another array and push all the variables in the new array.

$result=[];
foreach ($array as $v1) {
    foreach ($v1 as $v2) {
        array_push($result,$v2);
    }
}
Lucifyer
  • 158
  • 2
  • 11
  • This answer does not obey the asker's requirement to only push values into the result when the respective row key exists in the result array. https://3v4l.org/L0Kc1 – mickmackusa Sep 24 '22 at 00:52
0

Have you tried array_merge?

$mergedArray = [];
foreach ($array as $subArray) {
  $mergedArray = array_merge ($mergedArray, $subArray);
}

If that doesn't work, then you could probably use array_map to run a function on each sub array element to check if it is in the merged array before adding it.

$mergedArray = [];
foreach ($array as $subArray) {
  array_map(function($elm) {
    if (!in_array($elm, $mergedArray)) {
       $mergedArray[] = $elm;
    }, $subArray);
}
T0t3sMcG0t3s
  • 310
  • 1
  • 8
  • The first snippet does not obey the asker's requirement to only push values into the result when the respective row key exists in the result array. https://3v4l.org/NojaL and the second snippet simply does not run. https://3v4l.org/RtUHE – mickmackusa Sep 24 '22 at 00:54
0

You were very close, but you need to allow your script to restart the full array loop after consolidating data.

I recommend a do{}while() loop so that the inner processing can be repeated until there are no qualifying/moveable rows.

A nested loop is then used to search for first level keys that match any of the row values. Make the rows modifiable by reference with & -- this will ensure that the data manipulations are upon the original array and not merely a copy of the original array.

When there is a matching key, push the entire found row into the parent row, then remove the now-empty row from the original array, then toggle the flag indicating that another loop is required, then break

Code: (Demo)

do {
    $changes = false;
    foreach ($array as $k => &$row) {
        foreach ($row as $v) {
            if (isset($array[$v])) {
                array_push($array[$k], ...$array[$v]);
                unset($array[$v]);
                $changes = true;
            }
        }
    }
} while($changes);
var_export($array);
mickmackusa
  • 43,625
  • 12
  • 83
  • 136