PHP - Find the difference / subtraction between the values of two arrays - php

I am getting values of two company stocks through a third party website using an API. These are output as two arrays e.g.
$companyA = array([0] => 100 [1] => 100.20 [2] => 103.20);
$companyB = array([0] => 99 [1] => 101.30 [2] => 105.50);
Each key [0],[1],[2], etc.. represents a day and is the same day for both stock dates. I would like to try and find the difference in values in the array by doing a subtraction for each value. i.e. 100 - 99, 100.20-101.30, 103.20 - 105.50, etc...
I tried array_diff but it's not working.
Thank you.

You can use array_map
$result = array_map(function ($firstElement, $secondElement) {
return $firstElement - $secondElement;
}, $companyA, $companyB);

You can also try this with basics:
<?
$companyA = array(100,100.20,103.20);
$companyB = array(99,101.30,105.50);
$newArr = array();
foreach ($companyA as $key => $value) {
$newArr[] = ($value-$companyB[$key]);
}
echo "<pre>";
print_r($newArr);
?>
Result:
Array
(
[0] => 1
[1] => -1.1
[2] => -2.3
)

Related

Need to convert array of index array to single dimension index array in php

I need to convert array of index array to single dimension array.
$a=[];
$a[0]=[1,2,3];
$a[1]=[4,5,6];
$a[2]=[7,8,9];
$a[3]=[1,4,7];
I need to merge these arrays as single array. Is there any built in function available for this? The expected output is
[1,2,3,4,5,6,7,8,9,1,4,7]
That output must be an single dimension index array
You can simple use foreach like:
$a=[];
$a[0]=[1,2,3];
$a[1]=[4,5,6];
$a[2]=[7,8,9];
$a[3]=[1,4,7];
$b = [];
foreach($a as $array){
foreach($array as $value){
$b[] = $value;
}
}
print_r($b);
Result:
Array (
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
[6] => 7
[7] => 8
[8] => 9
[9] => 1
[10] => 4
[11] => 7 )
Suggest from #catcon you can use array_merge like:
$new_array = array_merge(...$a)
Reference:
array_merge
This is the correct solution refereed from How to Flatten a Multidimensional Array?
$a=[];
$a[0]=[1,2,3];
$a[1]=[4,5,6];
$a[2]=[7,8,9];
$a[3]=[1,4,7];
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($a));
$output=iterator_to_array($it, FALSE);
$result = array_merge(...$a);
print_r($result);
The easiest way
From this question link:
<?php
$a=[];
$a[0]=[1,2,3];
$a[1]=[4,5,6];
$a[2]=[7,8,9];
$a[3]=[1,4,7];
$result = [];
array_walk_recursive($a,function($val) use (&$result){ $result[] = $val; });
var_dump($result);
Demo

find duplicates in associative array PHP, compare their values

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

Sum of columns in multidimensional array without loops

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

Flatten 2D Array Into Separate Indexed Arrays

I have the array:
$total =array();
Array (
[0] => Array
(
[0] => 1
[1] => 3
)
[1] => Array
(
[0] => 6
[1] => 7
[2] => 8
)
[2] => Array
(
[0] => 9
[1] => 10
)
)
I need to dynamically change each array into an indexed array for a Cartesian function.
Here is how I need the code to look for the function to work correctly:
$count = cartesian(
Array(1,3),
Array(6,7,8),
Array(9,10)
);
Any help would be greatly appreciated! I have tried flattening, looping, using array_values, using just the array itself and I keep falling short.
Thanks
Nick
function cartesian() {
$_ = func_get_args();
if(count($_) == 0)
return array(array());
$a = array_shift($_);
$c = call_user_func_array(__FUNCTION__, $_);
$r = array();
foreach($a as $v)
foreach($c as $p)
$r[] = array_merge(array($v), $p);
return $r;
}
$count = call_user_func('cartesian', array($total));
print_r($count);
Your arrays already look exactly the way you want them to. array(1,3) is the same as array(0 => 1, 1 => 3) and both are an array with the value 1 at key 0 and 3 at key 1. Exactly what the debug output shows you.
It seems you just need to pass them as separate arguments to the function. E.g.:
cartesian($total[0], $total[1], $total[2])
For dynamic lengths of arrays, do:
call_user_func_array('cartesian', $total)
I believe that your $total array is multi-dimensional array with numeric indexed. So yo can try like this
$count = cartesian($total[0], $total[1], $total[2]);

Sort an array of alphabetic and numeric string-type elements ASC, but with numeric elements after alphabetic elements

I have an array of values which are either all-letters or all-numbers and need to sort them in an ascending fashion. Additionally, I want all-numeric values to be moved to the end of the array so that they occur after all of the non-numeric values.
$test = ["def", "yz", "abc", "jkl", "123", "789", "stu"];
If I run sort() on it I get:
Array
(
[0] => 123
[1] => 789
[2] => abc
[3] => def
[4] => jkl
[5] => stu
[6] => yz
)
but I'd like to see:
Array
(
[0] => abc
[1] => def
[2] => jkl
[3] => stu
[4] => yz
[5] => 123
[6] => 789
)
I tried array_reverse(), but that didn't seem to change anything. I'm at a loss for how to get the numbers last, but in ascending order.
What you need is sort but with a custom comparison function (usort).
The following code will get it done:
function myComparison($a, $b){
if(is_numeric($a) && !is_numeric($b))
return 1;
else if(!is_numeric($a) && is_numeric($b))
return -1;
else
return ($a < $b) ? -1 : 1;
}
$test = array("def", "yz", "abc", "jkl", "123", "789", "stu");
usort ( $test , 'myComparison' );
You could convert your numbers to integers before sorting:
$array = array("def", "yz", "abc", "jkl", "123", "789", "stu");
foreach ($array as $key => $value) {
if (ctype_digit($value)) {
$array[$key] = intval($value);
}
}
sort($array);
print_r($array);
Output:
Array
(
[0] => abc
[1] => def
[2] => jkl
[3] => stu
[4] => yz
[5] => 123
[6] => 789
)
In the following code is separate the data in two arrays: one is numerical the other is not and sort it and merge it.
$arr1 = $arr2 = array();
$foreach ($arr as $val) {
if (is_numeric($val)) {array_push($arr2, $val); }
else {array_push($arr1, $val);}
}
so you have to separate arrays whit numeric and non-numeric
sort($arr2);
sort($arr1);
$test = array_merge($arr2,$arr1);
You could do this using usort and a custom comparison function, but this sounds like more trouble than it's worth. I'd use sort, and then handle that output accordingly. It's not clear how you want to use it, but a simple way might be:
sort($test);
foreach ($test as $index=>$value) {
if (is_numeric($value)) {
$test[] = $value;
unset($test[$index]);
} else {
continue;
}
}
usort will probably be faster and it's going to do the comparisions once, while the other solutions mentioned thus far may be a little slower as they require iterating over some or all of the array before or after the sort
You do not need to engage any iterated processing for this task -- and therefore should not.
Use array_multisort() to sort the array numerically, then as strings (normally).
Code: (Demo)
array_multisort($test, SORT_NUMERIC, $test);

Categories