-1

I have no idea why this question has been marked as a duplicate, because the so-called duplicate is about using array_merge to combine arrays - this question is about combining element trees WITHIN an array.

Is there a way to combine individual elements and their subtrees within a PHP array? For instance, to convert this:

$test = array(
    "EW" => array(313, 1788),
    "SC" => array(670, 860),
    "FR" => array(704, 709),
    "UK" => array(423, 1733)
);

into this:

$test1 = array(
    "UK" => array(313, 423, 670, 860, 1733, 1788),
    "FR" => array(704, 709)
);

where the entries for EW and SC have been combined with those for UK.

array_combine and array_merge seem to work between arrays, not within them, so I'm not clear how to approach this.

donnek
  • 221
  • 1
  • 9
  • This question appears to be missing some vital context. How much variability will the data have? Is there any reason that you cannot hardcode the merging of the data? It looks as simple as https://3v4l.org/7L05r Do you need a loop for some reason? https://3v4l.org/qunsh – mickmackusa Mar 26 '23 at 22:02
  • This question is as vague as [Php array - merge only specific keys in single array,](https://stackoverflow.com/q/67355130/2943403) – mickmackusa Mar 26 '23 at 22:15
  • If you want to leverage a "key map" and fallback to the original key if it's not in the map: https://3v4l.org/367sM or with element spreading https://3v4l.org/pVlnD. Is it only the countries in the United Kingdom that you need to consolidate? Are there any other territories that need to be accommodated? – mickmackusa Mar 26 '23 at 22:49
  • All these seem to be based on the fact that you know which elements will be in the array, and that you will always want to combine the same ones. That isn't the case here - I don't know which elements will be there in advance, and I want to combine them in different ways in different contexts. Honk's answer does that admirably. – donnek Mar 27 '23 at 22:23
  • My first demo in my previous comment uses the same key mapping approach as Honk's answer except it uses more concise syntax. How can anyone (including yourself) design a script where you don't know how the mapping should be? – mickmackusa Mar 27 '23 at 23:31
  • Yes, neat, but a bit more opaque. The mapping may change depending on use-case, eg one colleague may want to combine A, B, C, another may not, or may want to combine C, D, E, depending on the report they're doing. So ideally the code should allow that to be handled. – donnek Mar 28 '23 at 11:06
  • **None** of that variability has been expressed in the question body. I wonder if this is arguing for argument's sake. I will be very happy to consider voting to reopen when the dynamic rules of this task are made plainly clear. Right now, there are a dozen or more ways to convert your input to that output. – mickmackusa Mar 28 '23 at 13:46
  • The question contained a MWE, and produced a solution that was workable for my situation. Occam's Razor? The question was answered and closed before you decided, post hoc, to (incorrectly) mark it as a duplicate... – donnek Mar 28 '23 at 15:20
  • I don't need it reopened, by the way, just unmarked as a duplicate, because it's misleading for users to have it point to a question that is quite different. – donnek Mar 28 '23 at 15:28
  • Again, this page is not yet a good fit for Stack Overflow and its readers until more clarity is given in the question. We don't reopen pages just to close them differently. The dupe target shows how to merge data -- this is what your snowflake question is asking. If there are more precise/dynamic requirements on a user-by-user basis, then the onus is on you to present that in the question. Believe me I want to answer. I do not benefit from closing this page. – mickmackusa Mar 28 '23 at 20:28
  • Your question refers to "concatenate 2 arrays", "join 2 arrays", "combining the arrays", but my question is about how to "combine elements WITHIN the array"? In mine, before using array_merge() you have to (1) set up a lookup array, and (2) check each tree against the lookup array. Those steps are not in your question - saying both questions use array_merge() is meaningless - it's like saying they both use PHP. Questions are supposed to be trimmed of excessive detail so that they are more generalisable. – donnek Mar 30 '23 at 08:38
  • I keep appealing for you to [edit] your question, but you instead argue via comments. AnantV's answer demonstrates that this task can, in fact, be done solely with `array_merge()`. – mickmackusa Mar 30 '23 at 11:11
  • I've already explained that (1) the question is not a duplicate (you can only use AnantV's suggestion if you know in advance which trees you will have, as AnantV says: "For small use case where you know the key and it will not change"), and (2) I have no idea what you have in mind as regards editing the question - as I said above, adding additional detail was not necessary for the question to get a good answer. Perhaps you could elaborate? – donnek Mar 30 '23 at 15:05
  • How should a solution know that EW and SC need to be merged into UK here but FR should not? As humans we can perhaps intuit you are referring to England, Wales, Scotland, and France, and that you want to merge states into their parent nations here, but is this simply a rote task you will never have to repeat or automate? If it is going to be repeated or automated, more detail is needed. – TylerH Mar 30 '23 at 15:50
  • I also don't know what you mean by "between arrays vs within them". array_merge() takes the contents of multiple arrays and merges those contents together into one array. There is no "between vs within". – TylerH Mar 30 '23 at 15:51
  • Re array_merge(), the crucial issue here is: is it possible to do what Honk did in his answer simply by following the advice given in the so-called duplicate (and nothing else)? If the answer is yes, then this question is a duplicate. If the answer is no, it's not. Re the SC, FR, etc, what they stand for is wholly irrelevant - they could be parrots, sausages, books, or anything - and so are the exact details of the setup. The crucial issue here is: did someone produce an answer which solved the use-case? If the answer is yes (which it is), the level of detail was adequate. – donnek Mar 30 '23 at 21:28

3 Answers3

0

One way to do it will be like this:

$test=array("EW"=>array(313, 1788), "SC"=>array(670, 860), "FR"=>array(704, 709), "UK"=>array(423, 1733));

//extract function converts all the keys to variables. 

extract($test);
$newarray['UK'] = array_merge($EW,$SC,$UK) ;
$newarray['FR'] = $FR;



echo "<pre>";
print_r($newarray);
echo "</pre>";

The result:

Array
(
    [UK] => Array
        (
            [0] => 313
            [1] => 1788
            [2] => 670
            [3] => 860
            [4] => 423
            [5] => 1733
        )

    [FR] => Array
        (
            [0] => 704
            [1] => 709
        )

)

For small use case where you know the key and it will not change this method is ok ...

Anant V
  • 299
  • 1
  • 9
  • Thanks for this - extract() is new to me. I'm still not quite clear how I'd keep track of the extracted arrays (there might be 20-30 of them), delete the merged ones, and combine the others into the new array. – donnek Mar 25 '23 at 20:51
0

You'll have to make a map of keys that have to be grouped with another key ($group_keys in the code below)

$test= [
    'EW' => [313, 1788], 
    'SC' => [670, 860], 
    'FR' => [704, 709], 
    'UK' => [423, 1733]
];

$group_keys=[
    'EW' => 'UK', 
    'SC' => 'UK'
];

$result = [];
foreach($test as $code => $values) {
    if (isset($group_keys[$code])) {
        $target = $group_keys[$code];
    }
    else {
        $target = $code;
    }
    if (isset($result[$target])) {
        $result[$target] = array_merge($result[$target], $values);
    }
    else {
        $result[$target] = $values;
    }
}

print_r($result);

Output:

Array
(
    [UK] => Array
        (
            [0] => 313
            [1] => 1788
            [2] => 670
            [3] => 860
            [4] => 423
            [5] => 1733
        )

    [FR] => Array
        (
            [0] => 704
            [1] => 709
        )

)
Honk der Hase
  • 2,459
  • 1
  • 14
  • 26
0

The function {array_merge_trees} will take an array, cut out the trees to be merged and merge them, remove them from the original array, and join the merged trees to what is left of the original array:

function array_merge_trees($original)
// Merge individual trees within an array.  
{
    $mergeme=array(UK, EW, SC, NI, DE, ES, FR, IT);  //The trees you want to merge.  IMPORTANT: The trees must exist within the original array, or you will get empty trees in the joined array.
    $trim=array_flip($mergeme);  // Convert the $mergeme values to keys.
    extract(array_intersect_key($original, $trim));  // Extract the trees in $mergeme - they will each become an array named after the key, eg $UK, $EW.
    $merged['UK']=array_merge($UK, $EW, $SC, $NI);  // Merge extracted trees as an element of a new array. IMPORTANT: The trees listed here must exist within the original array, or you will get empty trees in the joined array.
    sort($merged['UK']);  // Sort the values of the merged tree.
    // Repeat the above two lines if you want further merges, eg:
    $merged['EU'] = array_merge($DE, $ES, $FR, $IT);
    sort($merged['EU']);
    $trimmed=array_diff_key($original, $trim);  // Remove the trees to be merged from the original array.
    $rejoined=array_merge($trimmed, $merged);  // Join the merged trees with the non-merged trees from the original array.
    ksort($rejoined);  // Sort the keys of the rejoined array.
    return $rejoined;
}

To use it:

$original=array("EW"=>array(313, 1788), "SC"=>array(670, 860), "FR"=>array(704, 709), "UK"=>array(423, 1733), "DE"=>array(220, 260), "ES"=>array(1346, 1229), "NI"=>array(410, 453), "IT"=>array(134, 988));

$original=array_merge_trees($original);

echo "<pre>";
print_r($original);
echo "</pre>";

EDIT: Honk's answer is much better than this one.

donnek
  • 221
  • 1
  • 9