0

I have two arrays like below:

$array1 = array(
    'cover.xhtml',
    'title.xhtml',
    'copyright.xhtml',
    'dedication.xhtml',
    'toc_brief.xhtml',
    'toc.xhtml',
    'ch02_1.xhtml',
    'ch02_2.xhtml',
    'ch02_3.xhtml',
    'ch02_4.xhtml',
    'ch02_5.xhtml',
    'ch02_6.xhtml',
    'ch02_7.xhtml',
    'ch02_8.xhtml',
    'ch02_9.xhtml',
    'ch02_10.xhtml'
);

$array2 = array(
    '',
    'title.xhtml',
    'copyright.xhtml',
    'dedication.xhtml',
    'ch02_2.xhtml',
    'ch02_2#454.xhtml',
    'ch02_4.xhtml',
    'ch02_1.xhtml',
    'ch02_11.xhtml',
    'ch02_12.xhtml',
    ''
);

Desired sorted array:

array(
    'cover.xhtml',
    'title.xhtml',
    'copyright.xhtml',
    'dedication.xhtml',
    'toc_brief.xhtml',
    'toc.xhtml',
    'ch02_1.xhtml',
    'ch02_2.xhtml',
    'ch02_2#454.xhtml',
    'ch02_3.xhtml',
    'ch02_4.xhtml',
    'ch02_5.xhtml',
    'ch02_6.xhtml',
    'ch02_7.xhtml',
    'ch02_8.xhtml',
    'ch02_9.xhtml',
    'ch02_10.xhtml',
    'ch02_11.xhtml',
    'ch02_12.xhtml'
)

I tried with: call_user_func_array('array_merge', array_map(null, $array1, $array2));

This did not produce the result that I need.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Arghya
  • 3
  • 3

2 Answers2

0

If the order doesn't really matter, use:

$array3 = array_values(array_unique(array_filter(array_merge($array1, $array2))));

Output:

Array
(
    [0] => cover.xhtml
    [1] => title.xhtml
    [2] => copyright.xhtml
    [3] => dedication.xhtml
    [4] => toc_brief.xhtml
    [5] => toc.xhtml
    [6] => ch02_1.xhtml
    [7] => ch02_2.xhtml
    [8] => ch02_3.xhtml
    [9] => ch02_4.xhtml
    [10] => ch02_5.xhtml
    [11] => ch02_6.xhtml
    [12] => ch02_7.xhtml
    [13] => ch02_8.xhtml
    [14] => ch02_9.xhtml
    [15] => ch02_10.xhtml
    [16] => ch02_2#454.xhtml
    [17] => ch02_11.xhtml
    [18] => ch02_12.xhtml
)

Check it out here. The code does the following: merge -> remove empty -> remove duplicates -> fix keys.

FirstOne
  • 6,033
  • 7
  • 26
  • 45
  • Thanks for responding. The order really matters. So still trying to get a fix. – Arghya Jun 11 '17 at 13:45
  • @Arghya this will be tough, since it doesn't really follow a logical path. It's not alphabetical order, it's just ordered for the `ch` part. – FirstOne Jun 11 '17 at 13:50
  • hmm I understand and agree I am stuck into it since last 2 days – Arghya Jun 11 '17 at 14:05
  • Your suggestion was very helpful for me and helped me a lot to get an idea to fix the actual problem. Thank you so much. – Arghya Jun 19 '17 at 13:40
0

After merging and removing empty and duplicate strings, custom sorting the values is not exactly a trivial task, but with a lookup array to dictate the order, it doesn't need to be horrific either.

The call to usort() has two parts/rules.

  1. Isolate the leading substring before the first occurring dot or number with strtok(). Lookup the desired position of the substring to access a comparable integer value. (e.g. cover has an order value of 0 so it will be before all other values) In my demonstration, there is no fallback value when receiving ordering integers because the lookup is an exhaustive list. If your lookup will not contain all possible leading substrings, then you'll need to declare a default order integer for those occurrences.

  2. If there isn't a clear winner based on the first rule, break the tie with a natural sort comparison. While reviewing the output, I realized that the #454 substring was not being sorted as desired, so I added an adjustment to replace the # so that that values comes after its "parent" value.

Code: (Demo)

$customOrder = array_flip([
    'cover',
    'title',
    'copyright',
    'dedication',
    'toc_brief',
    'toc',
    'ch'
]);

$uniqueFiltered = array_unique(array_filter(array_merge($array1, $array2)));
usort(
    $uniqueFiltered,
    fn($a, $b) => 
        $customOrder[strtok($a, '.012345789')] <=> $customOrder[strtok($b, '.012345789')] #rule1
        ?: strnatcmp(...str_replace('#', '_', [$a, $b]))                                  #rule2
);
var_export($uniqueFiltered);

In fact, it is going to be more direct/efficient to call array_multisort() because it requires fewer iterated function calls. You might find it easier to read too. (The lookup array is still needed, but I didn't repeat it in the snippet.)

Code: (Demo)

$uniqueFiltered = array_unique(array_filter(array_merge($array1, $array2)));
array_multisort(
    array_map(fn($v) => $customOrder[strtok($v, '.012345789')], $uniqueFiltered), #rule1
    str_replace('#', '_', $uniqueFiltered),                                       #rule2
    SORT_NATURAL,                                                                 #rule2 flag
    $uniqueFiltered                                                               #array to modify
);
var_export($uniqueFiltered);
mickmackusa
  • 43,625
  • 12
  • 83
  • 136