How to sum array value of duplicate data - php

I have an array with some of same ID value as shown in below.
[
{"ID":"126871","total":"200.00","currency":"USD","name":"John"},
{"ID":"126872","total":"2000.00","currency":"Euro","name":"John"},
{"ID":"126872","total":"1000.00","currency":"Euro","name":"John"},
{"ID":"126872","total":"500.00","currency":"USD","name":"John"},
{"ID":"126872","total":"1000.00","currency":"Euro","name":"John"},
]
If the ID value is duplicate, sum the total value of the same currency. For the different currency of same ID, no need to sum total.
Here is what I want.
[
{"ID":"126871","total":"200.00","currency":"USD","name":"John"},
{"ID":"126872","total":"4000.00","currency":"Euro","name":"John"},
{"ID":"126872","total":"500.00","currency":"USD","name":"John"}
]
I am stuck with the above problem. I already tried as much as I can. But I got the wrong result. I'm very appreciative for any advice.

#Cloud I have made function for your requirement and Thanks #M. I. for look into this sum section.
$array = array(
array("ID" => "126871","total"=>"200.00","currency"=>"USD","name"=>"John"),
array("ID" => "126872","total"=>"2000.00","currency"=>"Euro","name"=>"John"),
array("ID" => "126872","total"=>"1000.00","currency"=>"Euro","name"=>"John"),
array("ID" => "126872","total"=>"500.00","currency"=>"USD","name"=>"John"),
array("ID" => "126872","total"=>"1000.00","currency"=>"Euro","name"=>"John"),
);
echo "<pre>";
print_r($array);
function unique_multidim_array($array, $key,$key1,$addedKey) {
$temp_array = array();
$i = 0;
$key_array = array();
$key1_array = array();
foreach($array as $val) {
if (!in_array($val[$key], $key_array) && !in_array($val[$key1], $key1_array)) {
$key_array[$i] = $val[$key];
$key1_array[$i] = $val[$key1];
$temp_array[$i] = $val;
}else{
$pkey = array_search($val[$key],$key_array);
$pkey1 = array_search($val[$key1],$key1_array);
if($pkey==$pkey1){
$temp_array[$pkey][$addedKey] += $val[$addedKey];
}else{
$key_array[$i] = $val[$key];
$key1_array[$i] = $val[$key1];
$temp_array[$i] = $val;
}
// die;
}
$i++;
}
return $temp_array;
}
$nArray = unique_multidim_array($array,"ID","currency","total");
// die;
print_r($nArray);
die;

You will need to:
Convert your json string to a php array with json_decode.
Loop through the rows and group them using compound temporary keys. In other words generate a single string from each row's ID & currency values and use that string as the temporary unique key.
Sum the grouped row's total values.
Then prepare the output array for its return to json by reindexing the rows and calling json_encode().
Code: (Demo)
$json='[
{"ID":"126871","total":"200.00","currency":"USD","name":"John"},
{"ID":"126872","total":"2000.00","currency":"Euro","name":"John"},
{"ID":"126872","total":"1000.00","currency":"Euro","name":"John"},
{"ID":"126872","total":"500.00","currency":"USD","name":"John"},
{"ID":"126872","total":"1000.00","currency":"Euro","name":"John"}
]';
$array=json_decode($json,true); // convert to array
foreach($array as $row){
if(!isset($result[$row['ID'].$row['currency']])){
$result[$row['ID'].$row['currency']]=$row; // on first occurrence, store the full row
}else{
$result[$row['ID'].$row['currency']]['total']+=$row['total']; // after first occurrence, add current total to stored total
}
}
$result=json_encode(array_values($result)); // reindex the array and convert to json
echo $result; // display
Output:
[
{"ID":"126871","total":"200.00","currency":"USD","name":"John"},
{"ID":"126872","total":4000,"currency":"Euro","name":"John"},
{"ID":"126872","total":"500.00","currency":"USD","name":"John"}
]

What: Create an array that is grouped by 'ID' and 'Currency'. Accumulate currency for duplicates.
How:
Add rows one at a time to an output array.
If group is not in the array then add it
If it is in the array then add the currency to the existing record.
Demonstration at eval.in
Code:
/** ----------------------------------------------
* Create an output array one row at a time.
*
* Group by Id and currency.
*
* #param array $groups
*
* #return array
*/
function getCurrencyGroups(array $groups)
{
$currencyGroups = array();
foreach ($groups as $item) {
$id = $item['ID'];
$currency = $item['currency'];
$amount = $item['total'];
if (!isset($currencyGroups[$id][$currency])) {
$currencyGroups[$id][$currency] = $amount;
}
else {
$currencyGroups[$id][$currency] += $amount;
}
}
return $currencyGroups;
}
Run it:
$currencyGroups = getCurrencyGroups($source);
Output:
array (size=2)
126871 =>
array (size=1)
'USD' => string '200.00' (length=6)
126872 =>
array (size=2)
'Euro' => float 4000
'USD' => string '500.00' (length=6)

I found myself in a similar situation except for I painted myself into a corner and needed to use the same array for input and output. I also found Manish response to be a little heavy-handed.
foreach($open_po_report as $pkey => &$po_line){
foreach($open_po_report as $dkey => $dupe_item){
//do not compare the exact same line
if($dupe_item['PoNo'].$dupe_item['Line'] === $po_line['PoNo'].$po_line['Line']){
continue;
}
//once you find a duplicate sum the qty to the original occurance
if($dupe_item['ItemVendorItem'] === $po_line['ItemVendorItem']){
$po_line['MyOrder']+=$dupe_item['MyOrder'];
unset($open_po_report[$dkey]);
}
//delete the duplicate entry
}
}

#Cloud Try this.
$array = array(array("ID" => "126871","total"=>"200.00","currency"=>"USD","name"=>"John",),array("ID" => "126871","total"=>"200.00","currency"=>"USD","name"=>"John",),array("ID" => "126872","total"=>"1000.00","currency"=>"Euro","name"=>"John",));
echo "<pre>";
print_r($array);
$unique = array_map('unserialize', array_unique(array_map('serialize', $array)));
Sure #Magnus Eriksson. I am explaining why we use 'serialize' and 'unserialize' in steps :
Step 1: Convert the multidimensional array to one-dimensional array
To convert the multidimensional array to a one-dimensional array, first generate byte stream representation of all the elements (including nested arrays) inside the array. serialize() function can generate byte stream representation of a value. To generate byte stream representation of all the elements, call serialize() function inside array_map() function as a callback function. The result will be a one dimensional array no matter how many levels the multidimensional array has.
Step 2: Make the values unique
To make this one dimensional array unique, use array_unique() function.
Step 3: Revert it to the multidimensional array
Though the array is now unique, the values looks like byte stream representation. To revert it back to the multidimensional array, use unserialize() function.
I hope now why i make this code.

Related

Find count of smaller no of elements in an array and the solution needs to be 2n

Hi i am stuck with a problem where in i have to find out the count of smaller no of element in an array i have implemented what we call as a brute force method but this isn't the optimised solution, can anyone help me out with the optimise solution for the code below
<?php
function find_small_count($arr){
$no_count = [];
foreach ($arr as $key => $value){
$no_count[$key] = 0;
foreach ($arr as $key1 => $value){
if ($arr[$key1] < $arr[$key]) {
$no_count[$key]++;
}
}
}
return $no_count;
}
print_r(find_small_count(['8','1','2','2','5']));
?>
Where in the expected Output should be [4,0,1,1,3]
I have three solutions for you. Let me explain
Working code sandbox
Solution 1
Use array_filter to return only qualified elements and then count the filtered array to get the count.
## Solution 1:
function find_small_count($arr)
{
$response = [];
foreach ($arr as $valueToSearch) {
$filtered = array_filter($arr, function ($value) use ($valueToSearch) {
return $value < $valueToSearch;
});
$response[] = ['valueToSearch' => $valueToSearch, 'count' => count($filtered)];
}
return $response;
}
print_r(find_small_count(['8', '1', '2', '2', '5']));
Solution 2
Sort the array in ascending order. When doing so your array has all numbers lesser than the current element appearing before it (in the array). Therefore the key for the array will be the count of all those numbers that are less than the current value, excluding the current number (keys start with 0).
Exception will be when a number appears twice, like 2 in your case. If we were to use key as the count in your case the first 2 will have count 1 and second 2 will have count 2, which is incorrect. Do note that the first 2 does give you the correct count.
To avoid this we can use array_unique and remove the duplicates. That will leave you with only one 2 in your response (the first one) and will give you the correct count.
You may think what about 5. For that we can fallback on the behavior of array_unique to preserve the keys. Hence even after array_unique 5 will retain its key, ie. 3. And our objective is accomplished. The only side effect is that the response will be [4,0,1,3] instead of [4,0,1,1,3]. So if that works you can use this method.
function find_small_count_two($arr){
$response = [];
sort($arr);
$arrUniqueAndSorted = array_unique($arr);
foreach ($arrUniqueAndSorted as $key => $value){
$response[] = ['valueToSearch' => $value, 'count' => $key];
}
return $response;
}
print_r(find_small_count_two(['8', '1', '2', '2', '5']));
Solution 3
Use array_search. From the docs
Searches the array for a given value and returns the first corresponding key if successful
Same logic as Solution 2 but this one avoids array_unique
function find_small_count_three($arr){
$response = [];
sort($arr);
foreach ($arr as $valueToCount){
$count =array_search($valueToCount, $arr);
$response[] = ['valueToSearch' => $valueToCount, 'count' => $count];
}
return $response;
}

PHP removing a specific array from a multidimensional array

I have a multidimensional array in PHP where I need to remove one array based on the value of an item in one of the arrays:
Example Array
array(
"0"=>array("0"=>"joe", "1"=>"2018-07-18 09:00:00"),
"1"=>array("0"=>"tom", "1"=>"2018-07-17 09:00:00"),
"2"=>array("0"=>"joe", "1"=>"2018-07-14 09:00:00")
)
I know that I want to remove the array that contains joe in key 0, but I only want to remove the array that contains joe with the most current date in key1. The following output is what I'm trying to accomplish:
array(
"0"=>array("0"=>"tom", "1"=>"2018-07-17 09:00:00"),
"1"=>array("0"=>"joe", "1"=>"2018-07-14 09:00:00")
)
Is there a simple way to do this in PHP aside from looping through each array?
Here is a non looping method that uses array_intersect and array_column to find the "Joe's" and then deletes the maximum array_key since I first sort the array on dates.
usort($arr, function($a, $b) {
return $a[1] <=> $b[1];
}); // This returns the array sorted by date
// Array_column grabs all the names in the array to a single array.
// Array_intersect matches it to the name "Joe" and returns the names and keys of "Joe"
$joes = array_intersect(array_column($arr, 0), ["joe"]);
// Array_keys grabs the keys from the array as values
// Max finds the maximum value (key)
$current = max(array_keys($joes));
unset($arr[$current]);
var_dump($arr);
https://3v4l.org/mah6K
Edit forgot to add the array_values() if you want to reset the keys in the array.
Just add $arr = array_values($arr); after the unset.
I would go about it like this:
<?php
$foo = array(
"0"=>array("0"=>"joe", "1"=>"2018-07-18 09:00:00"),
"1"=>array("0"=>"tom", "1"=>"2018-07-17 09:00:00"),
"2"=>array("0"=>"joe", "1"=>"2018-07-14 09:00:00")
);
$tmp = [];
foreach($foo as $k => $v) {
if ($v[0] === 'joe') {
$tmp[$v[1]] = $k;
}
}
if (!empty($tmp)) {
sort($tmp); //think that is sane with date format?
unset($foo[reset($tmp)]);
}
var_dump($foo);
Not sure if you don't want to loop on principal or what... I tend to go for readability. Find all occurrences of joe. Sort on date. Remove the most recent by key.

PHP - How to re-order data within a multidimensional array with only one reliable preceding string?

I am being passed inconsistent data. The problem is the individual rows of $data_array are not consistently in the same sequence but each has a reliable "text:" preceding the value.
Each row contains about 120 elements of data. I only need 24 of those elements.
It's also possible one of the elements I need could be missing, such as "cost".
(I'm using php version 5.4)
-- Task:
Using $order_array, create a new $data_array_new by reordering the data in each "row" into the same sequence as $order_array.
If an elements is missing from a row insert "NA".
Once the elements are in the correct sequence the "text" is no longer required.
$order_array = array("price", "cost", "vol", "eps")
$data_array = Array (
$one = Array ("cost":43.40, "vol":44000, "eps":1.27, "price":65.00),
$two = Array ("eps":5.14, "price":33.14, "vol":657000),
$thr = Array ("vol":650000, "cost":66.67, "eps":1.33, "price":44.31),
);
The resulting ouput should appear with the data in this order: ("price", "cost", "vol", "eps")
$data_array_new = Array (
$one = Array (65.00,43.40,44000,1.27),
$two = Array (33.14,"NA",657000,5.14),
$thr = Array (44.31,66.67,650000,1.33),
);
$data_array_new = [];
foreach ($data_array as $index => $data) {
$data_array_new[$index] = [];
foreach ($order_array as $key) {
if (isset($data[$key])) {
$data_array_new[$index][] = $data[$key];
} else {
$data_array_new[$index][] = 'NA';
}
}
}
You can view the original incoming data here: https://api.iextrading.com/1.0/stock/market/batch?symbols=aapl,tsla,ge&types=quote,earnings,stats
Here is the answer from : Andreas
Use json_decode on the string with the second parameter true and you get a associative array as output.
$url = "https://api.iextrading.com/1.0/stock/market/batch?
symbols=aapl,tsla,ge&types=quote,earnings,stats";
$arr = json_decode(file_get_contents($url), true);
Var_dump($arr);
See here;
I copied the string from the page and posted it as $str.
https://3v4l.org/duWrI
Two steps is all that is needed.

Find values in PHP Array and calculate

I am trying to make a function where I get data from specific positions in an array, and then add(plus) the results together. Something like this:
$specificPositionsInArray = "1,4,12,27,40,42,48,49,52,53,56,58";
$dataArray = "1,2,3,4,5,6,7,8"; // More than hundred values.
myfunction($specificPositionsInArray) {
// Find position in array, based on $specificPositionsInArray and then
// plus the value with the previous value
// that is found in the $specificPositionsInArray.
// Something like:
$value = $value + $newValue;
return $value;
}
So if $specificPositionsInArray was 1,3,5
The $value that should be returned would be: 9 (1+3+5) (based on the $dataArray).
Maybe there is another way to do it, like without the function.
Here's a functional approach:
$specificPositionsInArray = array(1,3,7,6);
$dataArray = array(1,2,3,4,5,6,7,8);
function totalFromArrays($specificPositionsInArray, $dataArray) {
foreach ($specificPositionsInArray as $s){
$total += $dataArray[$s];
}
return $total;
}
$total = totalFromArrays($specificPositionsInArray, $dataArray);
echo $total;
You should look into arrays and how to handle them, you could have found the solution pretty easily. http://www.php.net/manual/en/book.array.php
//$specificPositionsInArray = array(1,4,12,27,40,42,48,49,52,53,56,58);
$specificPositionsInArray = array(1,3,5);
$dataArray = array(1,2,3,4,5,6,7,8);
$total=0;
foreach($specificPositionsInArray as $k => $v){
$total += $dataArray[$v-1];
}
echo $total;
The weird part about this is the $v-1 but because of how you want to handle the addition of the items, and an array starts with element 0, you have to subtract 1 to get to the right value.
So you want to do something like this:
$dataArray = array(1,2,3,4,5...); // 100+ values, not necessarily all integers or in ascending order
$specificPositions = array(1, 3, 5);
function addSpecificPositions($data, $positions) {
$sum = 0;
foreach($positions as $p)
$sum += $data[$p];
return $sum;
}
If you really want to keep your list of values in a string (like you have it in your example), you'll have to do an explode first to get them in array form.
Since it looks like your array is using numeric values for the keys this should be fairly easy to calculate. I refactored your code a little to make it easier to read:
$specificPositionsInArray = array(1,4,6,7);
By default PHP will assign numeric keys to each value in your array, so it will look like this to the interpreter.
array(
[0] => 1,
[1] => 4,
[2] => 6,
[3] => 7
)
This is the same for all arrays unless you specify a numeric or mixed key. Since the data array seems to just be values, too, and no keys are specified, you can simply target them with the key that they will be associated with. Say I use your array example:
$dataArray = array(1,2,3,4,5,6,7,8);
This will look like this to the parser:
array(
[0] => 1,
[1] => 2,
[2] => 3,
[3] => 4,
[4] => 5,
[5] => 6,
[6] => 7,
[7] => 8
)
If you wanted to select the number 6 from this array, you actually need to use $dataArray[5] since array keys start at zero. So for your function you would do this:
$specificPositionsInArray = array(1,4,6,7);
$dataArray = array(1,2,3,4,5,6,7,8);
calculate_array($specificPositionsInArray, $dataArray); // Returns 18
function calculate_array($keys, $data){
$final_value = 0; // Set final value to 0 to start
// Loop through values
foreach($keys as $key){
// Add the keys to our starting value
$final_value += $data[$key-1]; // minus 1 from key so that key position is human readable
}
// return the sum of the values
return $final_value;
}

Convert this associative array to a string or single indexed array

I need to convert this array into a single dimensional indexed array or a string. Happy to discard the first key (0, 1) and just keep the values.
$security_check_whitelist = array
0 =>
array
'whitelisted_words' => string 'Happy' (length=8)
1 =>
array
'whitelisted_words' => string 'Sad' (length=5)
I tried array_values(), but it returned the exact same array structure.
This works:
$array_walker = 0;
$array_size = count($security_check_whitelist);
while($array_walker <= $array_size)
{
foreach($security_check_whitelist[$array_walker] as $security_check_whitelist_value)
{
$security_check[] = $security_check_whitelist_value;
}
$array_walker++;
}
But it returns:
Warning: Invalid argument supplied for
foreach()
How can I convert the associative array without receiving the warning message? Is there a better way?
foreach ($security_check_whitelist as &$item) {
$item = $item['whitelisted_words'];
}
Or simply:
$security_check_whitelist = array_map('current', $security_check_whitelist);
The problem here could be that you should only walk up to N-1, so $array_walker < $array_size.
So is "whitelisted_words" an array as well? If so, I think the following would work:
$single_dim_array = array();
foreach(array_values($security_check_whitelist) as $item) {
foreach($item['whitelisted_words'] as $word) {
$single_dim_array[] = $word;
}
}
Then the variable $single_dim_array contains all your whitelisted words.

Categories