0

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!

  • 2
    An example of the output you want would be really useful here, specifically how you want to identify which original array data came from – RiggsFolly Dec 10 '20 at 13:09
  • _"...the keys requirement to reference which array the value originally came from."_ is the part that puzzles me the most. An example would truly benefit you. – El_Vanja Dec 10 '20 at 13:13
  • @RiggsFolly I'm not entirely certain to be honest. I have prototyped this in HTML and have built a select list which uses data attributes with the key name (e.g. ``) so need to build an array which will be suitable for generating this output. What can you suggest for that, if anything? – Kaleb Thompson Dec 10 '20 at 13:19
  • It would still be useful to see which data you believe should reach the final array (from the example you give) You do realise that the KEYS you mention of these arrays are 0,1,2,3,4,5,6,7,8,9,10 and 0,1,2,3 – RiggsFolly Dec 10 '20 at 13:25
  • @El_Vanja I have added an example, and my desired output. I am not entirely certain the desired output is actually desired, or if there is a better way. – Kaleb Thompson Dec 10 '20 at 13:26

1 Answers1

2

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
)
*/
AterLux
  • 4,566
  • 2
  • 10
  • 13
  • That is exactly what I was looking to achieve. Now I can just do a `foreach $result as $lang => $type` to achieve my desired select list. Many thanks for your insights! – Kaleb Thompson Dec 10 '20 at 13:39