This is my array:
[0] => Array
(
[0] => SupSKU
[1] => MfrSKU
[2] => Cost
)
[1] => Array
(
[0] => A
[1] => 11742-4
[2] => 47.25
)
[2] => Array
(
[0] => B
[1] => 11742-4
[2] => 283.5
)
[3] => Array
(
[0] => C
[1] => 0904101
[2] => 995
)
I want to find duplicates values in Mfrsku value, in this example that is 11742-4, then compare their prices, and save bigger price SupSku value.
So my output will be
$final_output => Array (
[0] => B
)
I tried with this but this only retun empty array
array_unique(array_diff_assoc($ar,array_unique($ar)));
This is probably not the best performance, it got more nested than I wanted.
I use array_column and array_count_values to get how many times they are in the array, then array_diff removes the unique values.
I loop the duplicates and find the maximum prices that is associated to the duplicate and save them in an associative array.
$Mfr= array_column($arr, 1);
$dupes = array_diff(array_count_values($Mfr), [1]);
foreach($dupes as $key => $val){
$res[$key] = max(array_intersect_key(array_column($arr, 2), array_intersect($Mfr, [$key])));
}
var_dump($res);
/*
array(1) {
["11742-4"]=>
string(5) "283.5"
}
*/
https://3v4l.org/8v1Q0
I now save the intersect in a temporary array that I then can search in order to find what key has the maximum value.
I then use this key to get the [0] value which is "B".
$Mfr= array_column($arr, 1);
$dupes = array_diff(array_count_values($Mfr), [1]);
foreach($dupes as $key => $val){
$temp = array_intersect_key(array_column($arr, 2), array_intersect($Mfr, [$key]));
$res[$key] = $arr[array_search(max($temp), $temp)][0];
}
var_dump($res);
/*
array(1) {
["11742-4"]=>
string(1) "B"
}
*/
https://3v4l.org/dSpBi
I reworked the code in order to make it faster.
I used to use lots of loops in the background with array_intersect and array_column.
This code will now do more looping "front end" but instead create a multidimensional associative array that is quick to manipulate.
The code first creates a new array with [MfrSKU][SupSKU] = Cost.
Then I loop this array and if the count is one then there is no duplicates.
If there is duplicates I remove the minimum value and grab the keys and save them to the result array.
foreach(array_slice($arr,1) as $sub){
$new[$sub[1]][$sub[0]] = $sub[2];
}
foreach($new as $key => $sub){
if(count($sub) == 1){
continue;
}
$res[$key] = array_keys(array_diff($sub, [min($sub)]));
}
var_dump($res);
https://3v4l.org/20C2v
According to 3v4l it's about six times faster code in php 7.3.3
Related
This question already has answers here:
How to merge two arrays by summing the merged values [duplicate]
(3 answers)
Closed 5 months ago.
I would like to merge array by conditions. If array keys match then add the values, if not then retain the value.
Here are my arrays:
Array1
(
[1] => 199
[3] => 1306
[5] => 199
)
Array2
(
[3] => 199
[4] => 199
)
My desired result is:
Result
(
[1] => 199
[3] => 1505
[4] => 199
[5] => 199
)
I used if-else conditions, but it's repeating the value which is already matched.
Here is my coding attempt:
$all=array();
foreach($sall as $sskey => $ssvalue){
foreach($upgradesall as $uukey => $uuvalue){
//$sskey==$uukey?$all[] = array("id"=>$sskey, "amount"=>$ssvalue+$uuvalue):($sskey!=$uukey? $all[] = array("id"=>$sskey, "amount"=>$ssvalue):($uukey!=$sskey?$all[] = array("id"=>$uukey, "amount"=>$uuvalue):''));
if($sskey===$uukey){
$all[] = array("id"=>$sskey, "amount"=>$ssvalue+$uuvalue);
}elseif($sskey!=$uukey){
$all[] = array("id"=>$sskey, "amount"=>$ssvalue);
}elseif($uukey!=$sskey){
$all[] = array("id"=>$uukey, "amount"=>$uuvalue);
}
}
}
I think the problem is simpler than it looks. You really only need a conditional to preclude undefined offset notices. Just iterate all keys and values in both arrays and add the values to the corresponding key in the merged array.
foreach ([$a1, $a2] as $a) { // iterate both arrays
foreach ($a as $key => $value) { // iterate all keys+values
$merged[$key] = $value + ($merged[$key] ?? 0); // merge and add
}
}
Really, the line that actually does the addition ($merged[$key] = $value + ($merged[$key] ?? 0);) could be reduced to $merged[$key] += $value;. That would still work, but it would produce a bunch of undefined offset notices. So instead we can set the key equal to the value plus either the previous value (if it exists) or zero.
If you're still using PHP 5, you can use a ternary instead of the null coalescing operator (??), like this:
$merged[$key] = $value + (isset($merged[$key]) ? $merged[$key] : 0);
The output won't be in the same order shown in your desired result, but you can use ksort($merged); to accomplish that
First you can merge the arrays by merging all values in the same key:
$allKeys = array_unique(array_merge(array_keys($arr1),array_keys($arr2)));
$result = [];
foreach ($allKeys as $key) {
$result[$key] = [];
if (array_key_exists($key,$arr1)) {
$result[$key][] = $arr1[$key];
}
if (array_key_exists($key,$arr2)) {
$result[$key][] = $arr2[$key];
}
}
This will result in:
Array
(
[1] => Array
(
[0] => 199
)
[3] => Array
(
[0] => 1306
[1] => 199
)
[5] => Array
(
[0] => 199
)
[4] => Array
(
[0] => 199
)
)
Then you can map them according to your conditions:
$endResult = array_map('array_sum',$result);
Result:
Array
(
[1] => 199
[3] => 1505
[5] => 199
[4] => 199
)
If you want the keys to be sorted you can run them through a ksort as well
Check the code:
http://sandbox.onlinephpfunctions.com/code/3eb23310f0fd8de8174a5caf8b2b91d4b7562b6b
You could achieve that by
$all = array_merge($arr1,$arr2); // existing elements in arr1 are replaced by arr2 else merge into new array_merge
//then add replaced elememnts value
foreach($arr1 as $k=>$v)
{
if(array_key_exists($k,$all))
{
$all[$k] = $all[$k] + $v;
}
}
How can I count in a multidimensional array the number of element with a special condition ?
Array
(
[0] => Array
(
[item] => 'Banana'
)
[1] => Array
(
[item] => 'Banana'
)
[2] => Array
(
[item] => 'Cherry'
)
[3] => Array
(
[item] => 'Apple'
)
)
For example, for this array I should find 2 for Banana.
Si I tried:
$i=0;
foreach($array as $arr) {
if($arr[item]=='Banana') { $i++; }
}
Is there a better solution please ?
Thanks.
Method 1:
Using built-in functions - array_column and array_count_values:
print_r(array_count_values(array_column($arr,'item')));
Method 2:
Using foreach with simple logic of making your fruit as key and its count as value:
$arr = [
["item"=>"Banana"],
["item"=>"Banana"],
["item"=>"Cherry"],
["item"=>"Apple"]
];
$countArr = [];
foreach ($arr as $value) {
$item = $value['item'];
if(array_key_exists($item, $countArr)) // If key exists, increment its value
$countArr[$item]++;
else // Otherwise, assign new key
$countArr[$item] = 1;
}
print_r($countArr);
Final result in both case would be:
Array
(
[Banana] => 2
[Cherry] => 1
[Apple] => 1
)
So when you want Banana's count, you can get it like this:
echo $countArr['Banana'];
Use array_count_values(), it is pretty straight forward:
foreach($array as $arr) {
$new[] = $arr['item'];
}
print_r(array_count_values($new));
On a side note, there isn't anything wrong with your approach, unless you want to count all values. Also on a side note, I think you'll find a foreach() will eek out a slightly faster time than array_column(), especially on a large array.
I'm used to analysing data in R and have a hard time figuring out array in PHP.
Given the following array ($dat), what is the easiest way to get the total number of all females?
print("<pre>".print_r($dat,true)."</pre>");
Array
(
[0] => Array
(
[0] => female
[1] => blue
[2] => 62
)
[1] => Array
(
[0] => female
[1] => red
[2] => 22
)
[2] => Array
(
[0] => male
[1] => blue
[2] => 21
)
)
I'm doing this:
foreach($dat as $row) {
if($row[0]=='female') {
$females = $females + $row[2];
}
}
But there must be a way without loops!
Isn't there something like sum($dat[][2])?
Result for this sample should be 84
It seems I misinterpreted your question...
To obtain the sum, you can use array_reduce instead of a foreach loop (although it's not going to be much of an improvement):
array_reduce($dat, function($prev,$curr){return $prev+($curr[0]==='female'?$curr[2]:0);}, 0);
To obtain the number of elements containing 'female', You could use count with array_filter:
echo count(array_filter($dat, function($x){return in_array('female', $x);}));
This filters the array for any sub-arrays that contain the string female and returns the number of elements.
If you're sure that the string 'female' is always the zeroth element of the array, you could simplify the function slightly:
echo count(array_filter($dat, function($x){return $x[0]==='female';}));
You can array_reduce your array to a sum that way :
$array[0] = array('female', 2);
$array[1] = array('female', 5);
$array[2] = array('male', 2);
$sum = array_reduce($array, function ($value, $item) {
if ($item[0] == 'female') $value += $item[1];
return $value;
}, 0);
var_dump($sum);
Output :
7
I'm new to PHP so I'm not sure how to optimize this code.
I execute a Python script from PHP and the $output variable returned is an array of arrays.
exec (" /Users/$USER/anaconda/bin/python /Applications/MAMP/cgi-bin/Evaluation1.py",$output)
Each array within the $output array contains one string value separated by commas. So $output is Array ( [0] => 1, 好, 0 [1] => 2, 妈妈, 3), etc.
In each array within the $output array, I use explode on the string value to create an array, and add it to my new $output array called $output2
$output2 = array();
foreach($output as $value){
$myArray = explode(',', $value);
$output2[] = $myArray;
}
Is there a way to just replace/overwrite the string value in the arrays within $output with the new array, instead of adding each item to a new $output2 array?
You could use array_walk to do the loop over output. You pass in a callback function that is called for each value by reference so any changes to the passed in value stick to the array.
Test data:
$output = array(
'1,A,2',
'2,B,3',
'3,C,4'
);
PHP >= 5.3.0
array_walk($output, function(&$val){ $val = explode(',', $val); } );
Older PHP
function mySplit(&$val){
$val = explode(',', $val);
}
array_walk($output, 'mySplit');
Both output:
Array
(
[0] => Array
(
[0] => 1
[1] => A
[2] => 2
)
[1] => Array
(
[0] => 2
[1] => B
[2] => 3
)
[2] => Array
(
[0] => 3
[1] => C
[2] => 4
)
)
Some great answers already. Just adding this for completeness.
$ar = array(
"1,2,3",
"4,5,6"
);
foreach($ar as $k => $v) {
$ar[$k] = explode(',', $v);
}
Wold be interesting to see a a performance difference of the different methods although i doubt it would be much.
Hello all,
Array (
[0] => Array ( [id] => 242)
[1] => Array ( [id] => 24)
[2] => Array ( [id] => 234)
[3] => Array ( [id] => 244)
)
Array (
[0] => 24
[1] => 242
[2] => 244
)
When I used print_r(), I got above two arrays. Now, I need to filter two arrays and get uncommon values so my output will be 234
I would guess you mean array_diff, which returns you the set of elements that only exists in one of the arrays. You might have to run it twice however, if you don't know which array is the superset:
$diff = array_merge(array_diff($a1, $a2), array_diff($a2, $a1));
Oh and if the first array is nested like that, convert it first into a value list with $a1 = array_map("current", $a1) or something.
do a a foreach to go through the array, and then use something like in_array to do a test to see if any of the keys within the first array exists
$array3 = array();
foreach ($array1 as $v)
{
if !(in_array($v['ID'], $array2))
{
$array3[] = $v;
}
}
$array3 = array_unique($array3);
$array3 will return a list of non existant ID's (that didn't exist in $array2)
create two arrays with simply all the values in them, and then do
$arrayResult = $array1;
foreach($array1 as $id => $val) {
if !isset($array2[$id]) {
$arrayResult[] = $id;
}
}
foreach($array2 as $id => $val) {
if !isset($array1[$id]) {
$arrayResult[] = $id;
}
}
and then $arrayResult will have all uncommon values!