Skip to content
Advertisement

Merge PHP arrays to create named keys and unique values

I have an object which contains 3 arrays, any of which may be empty, it is feasible all three can be empty, so I need to handle that requirement too.

Here’s an example of the object:

{
    "lang_read": [],
    "lang_write": ["es", "ca", "zh", "en", "de", "he", "it", "ar", "ko", "pt", "ru"],
    "lang_listen": ["es", "ca", "en", "fr"]
}

I need to merge these 3 arrays into a single array with unique values, using the existing keys so that the output contains a reference to which array the merged array came from. Furthermore, the output must prefer the arrays in the order lang_listen, lang_read then lang_write.

Output should allow these to be listed in a HTML select list, so that the end user only selects one option.

I tried to do this, and managed to merge the arrays for unique values, but am stuck with the ordering requirement, and the keys requirement to reference which array the value originally came from with the following:

$mergedLanguages = array_unique(array_merge($languages->lang_listen, $languages->lang_read, $languages->lang_write), SORT_REGULAR);

However, this just produced a new array with numerical keys, and I have no way of referencing which array the value came from originally.

As an example of the desired output, which may be totally incorrect:

{
    "languages": [
        "lang_listen" => array("es", "ca", "en", "fr"), 
        "lang_write" => array("zh", "de", "he", "it", "ar", "ko", "pt", "ru")
    ]
}

Then I found need to build an HTML select list from this, something like:

echo '<select>';
foreach ($languages as $namedIndex => $arrayValues) {
   foreach ($arrayValues as $value) {
      echo '<option value="'.$value.'" data-type="'.$namedIndex.'">'.$value.'</option>';
   }
}
echo '</select>';

Because the order of priority is lang_listen>lang_read>lang_write, as "es", "ca", "en" exist in both lang_read and lang_listen, it these should only exist in lang_listen as it has priority over lang_read.

Can anyone advise what is the best approach and how to achieve it? Thanks!

Advertisement

Answer

If the input arrays have numeric keys array_merge will renumber the output array.

To avoid that you can use simple + operation over arrays:

If a key exists in the left operand array, then it will not be added from the right operand.

<?php
$lang_read = [];
$lang_write = ["es", "ca", "zh", "en", "de", "he", "it", "ar", "ko", "pt", "ru"];
$lang_listen = ["es", "ca", "en", "fr"];

$result = $lang_listen + $lang_read  + $lang_write;

print_r($result);

/*
Array
(
    [0] => es
    [1] => ca
    [2] => en
    [3] => fr
    [4] => de
    [5] => he
    [6] => it
    [7] => ar
    [8] => ko
    [9] => pt
    [10] => ru
)
*/

But it still gives you no information about where the items came from. To get that information you can rearrange your arrays, so the language codes will be in keys, while values will store the source.

You can use array_fill_keys to do that.

<?php
$lang_read = ["he", "en"];
$lang_write = ["es", "ca", "zh", "en", "de", "he", "it", "ar", "ko", "pt", "ru"];
$lang_listen = ["es", "ca", "en", "fr"];

$result = array_fill_keys($lang_listen, 'listen')
        + array_fill_keys($lang_read, 'read')
        + array_fill_keys($lang_write, 'write');

print_r($result);

/*

Array
(
    [es] => listen
    [ca] => listen
    [en] => listen
    [fr] => listen
    [he] => read
    [zh] => write
    [de] => write
    [it] => write
    [ar] => write
    [ko] => write
    [pt] => write
    [ru] => write
)
*/
User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement