2

I want to merge every element of two arrays, BUT if a value is in both arrays, then only add the values from the array which has the biggest amount of that element. The result array does not need to be sorted in any special way, but I did it here for readability.

Sample input:

$array1 = [1, 4, 7, 3, 3, 3];
$array2 = [4, 0, 3, 4, 9, 9];

Desired result:

 [0, 1, 3, 3, 3, 4, 4, 7, 9, 9]
//a2 a1 a1 a1 a1 a2 a2 a1 a2 a2

Note, this will be used on big arrays, with unknown integer values. Is there a good way to do this that doesn't require too much time/processing power?

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
user1946831
  • 53
  • 1
  • 4
  • I don't know what you mean by "add the biggest amount there is of that element in a single array" – Mike Aug 06 '13 at 03:26
  • 1
    @Mike: Educated guess. There are three 3s in the first array. There's only one 3 in the second array. The "biggest amount" of 3s is three, so the resulting array should include `[...3, 3, 3, ...]`. – Mike Sherrill 'Cat Recall' Aug 06 '13 at 03:51
  • @MikeSherrill'Catcall' thanks for the explanation. Looks like the OP has gone away. – Mike Aug 06 '13 at 04:09

4 Answers4

0

Try this:

<?php

$array1 = [1, 4, 7, 3, 3, 3];
$array2 = [4, 0, 3, 4, 9, 9];

function min_merge($arr1, $arr2) {
    $arr1 = array_count_values($arr1);
    $arr2 = array_count_values($arr2);

    foreach ($arr2 as $index => $arr)
        if (!isset($arr1[$index]) || $arr > $arr1[$index])
            $arr1[$index] = $arr;

    foreach ($arr1 as $index => $arr)
        for ($i = 0; $i < $arr; $i++)
            $final[] = $index;

    return $final;
}

print_r(min_merge($array1, $array2));

Output:

Array (
    [0] => 1
    [1] => 4
    [2] => 4
    [3] => 7
    [4] => 3
    [5] => 3
    [6] => 3
    [7] => 0
    [8] => 9
    [9] => 9 
)

Unsorted, but it contains all the numbers from [0, 1, 3, 3, 3, 4, 4, 7, 9, 9].

Dave Chen
  • 10,887
  • 8
  • 39
  • 67
0
$count[0] = array_count_values($arr1);
$count[1] = array_count_values($arr2);
$out = array();
array_map(function($e) use(&$out, $count){
    $n1 = (isset($count[0][$e])) ? $count[0][$e] : 0;
    $n2 = (isset($count[1][$e])) ? $count[1][$e] : 0;
    $next = ($n2 > $n1) ? array_fill(0, $n2, $e) : array_fill(0, $n1, $e);
    $out = array_merge($out, $next);
}, array_keys($count[0] + $count[1]));
print_r($out);
Expedito
  • 7,771
  • 5
  • 30
  • 43
0
  1. My modernized rewrite of @DaveChen's answer using PSR-12 coding standards and eliminating single-use declarations. This approach uses one loop to determine the greater count for numbers shared by both value-count arrays, then a second loop to populate the result array. (Demo)

    $counts1 = array_count_values($array1);
    foreach (array_count_values($array2) as $number => $count) {
        if ($count > ($counts1[$number] ?? 0)) {
            $counts1[$number] = $count;
        }
    }
    $result = [];
    foreach ($counts1 as $number => $count) {
        array_push($result, ...array_fill(0, $count, $number));
    }
    var_export($result);
    
  2. My modernized rewrite of @Expedito's answer which does not abuse the array_map() (when array_map()'s return value is not used, use array_walk() for functional style programming), uses a foreach() loop to eliminate variable scope issues, and generally implements D.R.Y. techniques. (Demo)

    $counts1 = array_count_values($array1);
    $counts2 = array_count_values($array2);
    $result = [];
    foreach ($counts1 + $counts2 as $num => $cnt) { 
        array_push(
            $result,
            ...array_fill(
                0,
                max($counts1[$num] ?? 0, $counts2[$num] ?? 0),
                $num
            )
        );    
    }
    var_export($result);
    
  3. And I wanted to add a new approach of my own, despite the fact that it may or may not perform better than the other two snippets. The script makes one pass over the first value count arrays to populate a temporary array which demands which numbers from the first array should be represented in the result array. Then it isolates value intersections from the first array, value differences from the second array, then merges them. (Demo)

    $counts1 = array_count_values($array1);
    $counts2 = array_count_values($array2);
    $keepFrom1 = array_keys(
        array_filter(
            $counts1,
            fn($count, $number) => ($counts2[$number] ?? 0) <= $count,
            ARRAY_FILTER_USE_BOTH
        )
    );
    
    var_export(
        array_merge(
            array_intersect($array1, $keepFrom1),
            array_diff($array2, $keepFrom1)
        )
    );
    
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
-1

probably not the most optimized but

<?php
$one=[1, 4, 7, 3, 3, 3];
$two=[4, 0, 3, 4, 9, 9];
sort($one);
sort($two);
foreach($one as $el)
{
$combined[]=$el;
if (array_search($el,$two))
{
unset($two[array_search($el,$two)]);
}
}
foreach($two as $el)
{
$combined[]=$el;
}
sort($combined);
print_r($combined);
?>
chiliNUT
  • 18,989
  • 14
  • 66
  • 106