Given two arrays combine common values - php

$names = ['john','brian','john','steven','michael','paul','mark','paul','brian'];
$money = [2, 4, 3, 7, 5, 8, 20, -2, 4];
The indexes of $names and $money correspond to each other.
I need to find the most efficient way to add common $money to each $names and print only the even values.
For example, john appears two times, with 2 and 3 money. So johnhas 5 money.
Desired output:
mark: 20
brian: 8
paul: 6
I am thinking of looping through each array, but this is O(n^2) Is there an easier way?

Make associative array (hash) for result:
$names = ['john','brian','john','steven','michael','paul','mark','paul','brian'];
$money = [2, 4, 3, 7, 5, 8, 20, -2, 4];
$result = [];
for ($i = 0; $i < count($names); $i++) {
if (!isset($result[$names[$i]])) {
$result[$names[$i]] = 0;
}
$result[$names[$i]] += $money[$i];
}
arsort($result); // reverse (big first) sort by money
print_r($result);

just loop through names and use it keys for money array:
$names = ['john','brian','john','steven','michael','paul','mark','paul','brian'];
$money = [2, 4, 3, 7, 5, 8, 20, -2, 4];
$res = [];
foreach ($names as $key => $value) {
$res[$value] = isset($res[$value]) ? $res[$value] + $money[$key] : $money[$key];
}
var_dump($res);

You just have to loop through $names once and set name as key in a result- variable.
$names = ['john','brian','john','steven','michael','paul','mark','paul','brian'];
$money = [2, 4, 3, 7, 5, 8, 20, -2, 4];
$data = [];
foreach ($names as $key => $name) {
if (!isset($data[$name])) {
$data[$name] = 0;
}
$data[$name] += $money[$key];
}
print_r($data);

Maybe you'll need a check, if both arrays have the same size.
$names = ['john','brian','john','steven','michael','paul','mark','paul','brian'];
$money = [2, 4, 3, 7, 5, 8, 20, -2, 4];
$result = [];
foreach ($names as $index => $name) {
if (empty($result[$name]) {
$result[$name] = $money[$index];
} else {
$result[$name] += $money[$index];
}
}
print_r($result);

Related

How to combine 2 arrays with the condition that 2 and 5 values will be from the second array?

There are two arrays:
$arrOne = [1, 3, 4];
$arrTwo = [2, 5,];
$newArr = [];
How to merge to get like this;
$newArr = [1, 2, 3, 4, 5];
Now displays through one, this option is not suitable.
foreach ($arrOne as $k => $v) {
$newArr[] = $v;
$newArr[] = $arrTwo[$k];
}
Here is another example. Tthe values can be different in the array.
$arrOne = [154, 32, 15];
$arrTwo = [682, 124,];
Again for this example it is necessary that the values from the second array always be at 2 and 5 positions in the new array:
$newArr = [154, 682, 32, 15, 124];
You can use array_splice to merge the arrays in the intended way to the specific indices:
array_splice( $arrOne, 1, 0, $arrTwo[0]);
array_splice( $arrOne, 4, 0, $arrTwo[1]);
var_dump($arrOne);
Demo 1:
Using original data:
$arrOne = [1, 3, 4];
$arrTwo = [2, 5,];
https://3v4l.org/dAMav
Demo 2:
Using second set of data:
$arrOne = [154, 32, 15];
$arrTwo = [682, 124,];
https://3v4l.org/Xhl3K
You can use array_merge and sort functions to achieve this as following:
$newArr = array_merge($arrOne, $arrTwo); // it will be [1, 3, 4, 2, 5]
sort($newArr); // it will sort array [1, 2, 3, 4, 5]
You can use $newArr now which have sorted data
$arrOne = [1, 3, 4];
$arrTwo = [2, 5];
$newArr = [];
foreach($arrOne as $key => $one) {
switch($key) {
case 1:
$newArr[] = $arrTwo[0];
break;
case 4:
$newArr[] = $arrTwo[1];
break;
}
$newArr[] = $one;
}
if(count($newArr) < 5) {
$newArr[] = $arrTwo[1];
}
Demo link
Here we are considering there will be always two elements in second array
$arrayOne = [12,23,45,56,65,78,99];
$arrayTwo = [2,5];
$mergedArray = [];
foreach($arrayOne as $key => $value) {
$position = $key + 1;
if ($position === 2) {
$mergedArray[] = $arrayTwo[0];
} else if ($position === 4) {
$mergedArray[] = $arrayTwo[1];
}
$mergedArray[] = $value;
}

Index Third last occurrence of the integer, 1 in array

Below my code. I want to find the index/position of third last occurrence of the integer 1
$arr = array(2, 3, 1, 4, 5, 6, 1, 1,10,11,12,1);
$result = [];
foreach($arr as $key => $val){
$result[$val][] = $key;
}
echo end($result[1]);// 11 but it should be 6
Try this:
$arr = array(2, 3, 1, 4, 5, 6, 1, 1,10,11,12,1);
$result = [];
foreach($arr as $key => $val){
$result[$val][] = $key;
}
//count total record of $result[1] and third last index
$count = count($result[1]);
$thirdLastIndex = $count-3;
echo isset($result[1][$thirdLastIndex]) ? $result[1][$thirdLastIndex] : 'No record';
Demo

Group Array By Range Value

I have this array [1,1,2,2,2,3,4,4,5,6,6,6,7], may I group the array according to the range value, so get the final result:
'1-3' = [1,1,2,2,2,3]; // Count is 6
'4-5' = [4,4,5]; // Count is 3
'6-7' = [6,6,6,7]; // Count is 4
What you need I believe is:
function array_get_range($array, $min, $max) {
return array_filter($array, function($element) use ($min, $max) {
return $element >= $min && $element <= $max;
});
}
$array = [1,1,2,2,2,3,4,4,5,6,6,6,7];
$range13 = array_get_range($array, 1, 3); // [1, 1, 2, 2, 2, 3]
$range45 = array_get_range($array, 4, 5); // [4, 4, 5]
$range67 = array_get_range($array, 6, 7); // [6, 6, 6, 7]
Create a new array with your ranges, then iterate through the values and through the ranges inside. If the current value is inside the range, add the record to the current range:
<?php
$numbers = [1,1,2,2,2,3,4,4,5,6,6,6,7];
$counts = [];
$counts[] = ["values"=> [1, 3], "records" => []]; // first value in "values" is min, second is max
$counts[] = ["values"=> [4, 5], "records" => []];
$counts[] = ["values"=> [6, 7], "records" => []];
foreach ($numbers as $number) {
foreach ($counts as $key => &$value) {
if ($number >= $value["values"][0] && $number <= $value["values"][1]) { // if between the range, add it to the records
$value["records"][] = $number;
}
}
}
echo "<pre>";
foreach ($counts as $count) {
echo $count["values"][0]." - ".$count["values"][1]." = ".count($count["records"])." elements<br>";
}
Demo
I think array_intersect() and range() with sizeof()/count() does a cleaner job for this task. It eliminates the double-conditional.
Code: (Demo)
function count_range($array, $min, $max) {
return sizeof(array_intersect($array, range($min, $max)));
}
$array = [1, 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 7];
echo count_range($array, 1, 3); // 6 from [1, 1, 2, 2, 2, 3]
echo count_range($array, 4, 4); // 2 from [4, 4]
echo count_range($array, 2, 7); // 11 from [2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 7]
range() creates a whitelist array of one or more consecutive integers.
array_intersect() compares the input array and the whitelist array all at once.
sizeof() is just an alias of count() to determine how many elements were retained.

Combine two arrays but add Values of duplicate keys together

I have two arrays, $ids and $quants (ids and quantities of stock items) that need to be combined, but instead of replacing or removing duplicates, their values should be added together.
Currently I'm using array_combine() but this means that some of the quantities are lost where multiple of the same id exists.
e.g.
$ids = Array(1, 1, 2, 3);
$quants = Array(10, 20, 30, 40);
Desired output:
$combined = Array(
[1] => 30
[2] => 30
[3] => 40
)
Thanks in advance for any advice
$ids = Array(1, 1, 2, 3);
$quants = Array(10, 20, 30, 40);
$a = array_unique($ids);
$a = array_combine($a, array_fill(0, count($a), 0));
foreach($ids as $k=>$v) {
$a[$v] += $quants[$k];
}
print_r($a);
There isn't a built in function, so you have to do it yourself:
function my_array_combine($keys, $values)
{
if (count($keys) != count($values)) {
throw new InvalidArgumentException('More or less');
}
$result = array();
$values = array_values($values); // make sure it is indexed 0, 1, 2
foreach(array_values($keys) as $idx => $key) {
// Correspondending value is at $values[$idx];
if (isset($result[$key])) {
$result[$key] += $values[$idx];
} else {
$result[$key] = $values[$idx];
}
}
return $result;
}

Merge two flat arrays and omit values from one array when the other array has more occurrences of the same value

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?
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].
$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);
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);
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);
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)
)
);
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);
?>

Categories