I'm not able to find a solution for the given scenario where I have a multidimensional array in which I have to find the sum of the values of the arrays that have same ID.
demo.php
$array = array("1"=>array("id"=>"1", "total"=>"100"),
"2"=>array("id"=>"2", "total"=>"300"),
"3"=>array("id"=>"3", "total"=>"400"),
"4"=>array("id"=>"4", "total"=>"500"),
"5"=>array("id"=>"1", "total"=>"560"));
I want to get the sum of the total of all the duplicates IDs e.g 1 is the ID and the sum of the total would be 100 + 560 = 650.
One option is using array_reduce to summarize the array into an associative array.
$array = //....
$result = array_reduce( $array, function( $c, $v ){
if ( !isset( $c[ $v["id"] ] ) ) $c[ $v["id"] ] = 0;
$c[ $v["id"] ] += $v["total"];
return $c;
}, array() );
$result will be:
Array
(
[1] => 660
[2] => 300
[3] => 400
[4] => 500
)
UPDATE
Add another reduce to group the array first. The second reduce is to only include the array elements with more than one count.
$array = //....
$group = array_reduce( $array, function( $c, $v ){
if ( !isset( $c[ $v["id"] ] ) ) $c[ $v["id"] ] = [ "count" => 0, "total" => 0, "id" => $v["id"] ];
$c[ $v["id"] ]["count"] += 1;
$c[ $v["id"] ]["total"] += $v["total"];
return $c;
}, array() );
$result = array_reduce( $group, function( $c, $v ){
if ( $v["count"] > 1 ) $c[ $v["id"] ] = $v["total"];
return $c;
}, array() );
This will result to:
Array
(
[1] => 660
)
Another take while using a foreach:
$array = array("1"=>array("id"=>"1", "total"=>"100"),
"2"=>array("id"=>"2", "total"=>"300"),
"3"=>array("id"=>"3", "total"=>"400"),
"4"=>array("id"=>"4", "total"=>"500"),
"5"=>array("id"=>"1", "total"=>"560"));
$total = [];
foreach ($array as $sub) {
$total[$sub['id']] = isset($total[$sub['id']]) ? $total[$sub['id']] += $sub['total'] : $total[$sub['id']] = $sub['total'];
}
Output
Array
(
[1] => 660
[2] => 300
[3] => 400
[4] => 500
)
Live Example
Repl
Reading Material
Ternary Operator
You can use simple foreach loop to get the expected result
<?php
// Your code here!
$array = array("1"=>array("id"=>"1", "total"=>"100"),
"2"=>array("id"=>"2", "total"=>"300"),
"3"=>array("id"=>"3", "total"=>"400"),
"4"=>array("id"=>"4", "total"=>"500"),
"5"=>array("id"=>"1", "total"=>"560"));
$issetArray = array();
foreach ($array as $key => $value) {
if(isset($issetArray[$value['id']]))
{
$issetArray[$value['id']]['total'] += $value['total'];
}
else
{
$issetArray[$value['id']] = array();
$issetArray[$value['id']] = $value;
}
}
$result = array();
foreach ($issetArray as $value) {
array_push($result, $value);
}
print_r($result);
?>
Example: https://paiza.io/projects/Fnay-hbk4Cuf_-rMTL5AFA
If you want to use the external class tableArray and you want to preserve the structure of the input array try this:
$array = array("1"=>array("id"=>"1", "total"=>"100"),
"2"=>array("id"=>"2", "total"=>"300"),
"3"=>array("id"=>"3", "total"=>"400"),
"4"=>array("id"=>"4", "total"=>"500"),
"5"=>array("id"=>"1", "total"=>"560"));
$newData = tableArray::create($array)
->filterGroupSum('total',['id'])
->fetchAll()
;
$newData:
array (
0 =>
array (
'id' => "1",
'total' => 660,
),
1 =>
array (
'id' => "2",
'total' => 300,
),
2 =>
array (
'id' => "3",
'total' => 400,
),
3 =>
array (
'id' => "4",
'total' => 500,
),
)
Related
So, I am getting unique values from my MD array utilizing the following function:
function unique_multidim_array($array, $key) {
$temp_array = array();
$i = 0;
$key_array = array();
foreach( $array as $val ) {
if ( ! in_array( $val[$key], $key_array ) ) {
$key_array[$i] = $val[$key];
$temp_array[$i] = $val;
}
$i++;
}
return $temp_array;
}
My array is similar to the following:
Array (
[0] =>
Array (
'name' => 'Nevada'
)
[1] =>
Array (
'name' => 'Colorado'
)
[2] =>
Array (
'name' => 'Nevada'
)
[3] =>
Array (
'name' => 'Colorado'
)
[4] =>
Array (
'name' => 'Oklahoma'
)
[5] =>
Array (
'name' => 'Nevada'
)
[6] =>
Array (
'name' => 'Nevada'
)
)
And using the function (unique_multidim_array ( $term_arr, 'name' )) above I am getting a single Nevada and a single Colorado, however, it is not returning Oklahoma
What can I do to ensure that it will return unique values, even if there are no duplicates?
Your resulting array keeps the original indices, and, depending on how you are iterating over it, you might get unexpected results. Try resetting the indices:
function unique_multidim_array($array, $key) {
$temp_array = array();
$i = 0;
$key_array = array();
foreach( $array as $val ) {
if ( ! in_array( $val[$key], $key_array ) ) {
$key_array[$i] = $val[$key];
$temp_array[] = $val; // <--- remove the $i
}
$i++;
}
return $temp_array;
}
Or, as you say, array_values() will help too:
$term_arr = array_values ( unique_multidim_array ( $term_arr, 'name' ) );
PHP already has a function to remove duplicates from an array
array_unique(array)
should do the trick
I'm trying to build a tree-map from categories. I have the categories (I have a lot of categories and I want to remove duplicates and show them in a tree-map view with count) and I have the following code:
<?php
$cat = array(
"Sneakers/Men",
"Sneakers/Women",
"Accessories/Jewellery/Men",
"Accessories/Jewellery/Men",
"Accessories/Jewellery/Women",
"Accessories/Jewellery/Men/Bvlgari"
);
$out = [];
foreach ($cat as $str) {
$lookup = &$out;
$parts = explode("/", $str);
foreach ($parts as $part) {
$lookup = &$lookup[$part];
if (!isset($lookup))
$lookup = [];
if ($part == end($parts))
$lookup = is_array($lookup) ? 1 : ++$lookup;
}
}
print_r($out);
OUTPUT:
Array
(
[Sneakers] => Array
(
[Men] => 1
[Women] => 1
)
[Accessories] => Array
(
[Jewellery] => Array
(
[Men] => 3
[Women] => 1
)
)
)
I would like to be:
Array
(
[Sneakers] => Array
(
[Men] => 1
[Women] => 1
)
[Accessories] => Array
(
[Jewellery] => Array
(
[Men] => Array (
[Bvlgari] => 1
)
[Women] => 1
)
)
)
You're losing information with both of those formats and the suggested answer is not going to cut it. You do need recursion and each item needs to hold a count and children.
$cat_paths = [
'Sneakers/Men',
...
];
$cat_counts = $item = [# template of each item
'count' => 0,
'children' => [],
];
foreach ($cat_paths as $cat_path) {
$level = &$cat_counts;# use a reference for recursion
if ($cat_path) {# allow uncategorized to be in root of tree
$cat_path = explode('/', $cat_path);
do {
$cat = array_shift($cat_path);
if (!isset($level['children'][$cat])) {
$level['children'][$cat] = $item;
}
$level = &$level['children'][$cat];# step down into tree
} while ($cat_path);
}
$level['count']++;
}
unset($level);
input array
$input = array (
"group_name_1" => "audi",
"group_locations_1" => "tokyo,barcelona,paris",
"group_quantities_at_locations_1" => "1,2,7",
"group_name_2" => "ford",
"group_locations_2" => "london,prag",
"group_quantities_at_locations_2" => "3,6"
);
needed output form
$target_output = array (
"audi" => array ( "tokyo" => 1, "barcelona" => 2, "paris" => 7 ),
"ford" => array ( "london" => 3, "prag" => 6 )
);
notes 1:
number of groups are dynamic (user input). For example, additional to
"audi" and "ford"; there could be also "toyota", "mercedes".
Each groups has 3 subinfo: 1-name , 2-locations and 3-quantities for
locations.
Sequences in input are always same. 1st name, 2nd locations, 3rd
quantities.
Each group has proper order number always in input. (such as
"group_name_1 or group_locations_4)
notes 2: I've read array functions again. And tried various codes but I even couldn't get close.
Can you please help me.
assuming that group_name_x, group_locations_x and group_quantities_at_locations_x keys alwas exists in your $input array
$input = array(
"group_name_1" => "audi",
"group_locations_1" => "tokyo,barcelona,paris",
"group_quantities_at_locations_1" => "1,2,7",
"group_name_2" => "ford",
"group_locations_2" => "london,prag",
"group_quantities_at_locations_2" => "3,6"
);
$new_array = array();
foreach ($input as $key => $val) {
if (strpos($key, 'group_name') !== false) {
$new_array[$val] = array();
$group_no = $key[strlen($key) - 1];
$location_array = explode(',', $input["group_locations_{$group_no}"]);
$group_quantities_array = explode(',', $input["group_quantities_at_locations_{$group_no}"]);
$new_array[$val] = array_combine($location_array, $group_quantities_array);
}
}
print_r($new_array);
output:
Array
(
[audi] => Array
(
[tokyo] => 1
[barcelona] => 2
[paris] => 7
)
[ford] => Array
(
[london] => 3
[prag] => 6
)
)
<?php
$inputs = array (
"group_name_1" => "audi",
"group_locations_1" => "tokyo,barcelona,paris",
"group_quantities_at_locations_1" => "1,2,7",
"group_name_2" => "ford",
"group_locations_2" => "london,prag",
"group_quantities_at_locations_2" => "3,6"
);
$result = array();
foreach ($inputs as $key => $value) {
if (!preg_match('/group_name_([0-9]*)/', $key, $matches)) {
continue;
}
$locations = explode(',', $inputs['group_locations_' . $matches[1]]);
$quantities = explode(',', $inputs['group_quantities_at_locations_' . $matches[1]]);
$result[$value] = array_combine($locations, $quantities);
}
echo '<pre>';
var_dump($result);
echo '</pre>';
You can simply use array_walk like as
$result = [];
$chunked = array_chunk($input,3);
array_walk($chunked,function($v) use (&$result){
$result[$v[0]] = array_combine(explode(",",$v[1]),explode(",",$v[2]));
});
print_R($result);
Demo
I got main array keys a1 and a2.
$array1 = array(a1=>array(200,300,300), a2=>array(100,600,200));
$array2 = array(a1=>array('gen','gen2','gen'), a2=>array('gen2','gen3','gen3'));
I want my output to be
'a1'=>array(
'gen'=>200
'gen2'=>300
'gen'=>300
),
'a2'=>array(
'gen2'=>100
'gen3' =>600
'gen3' =>200
)
or
'a1'=>array(
'gen'=>500
'gen2'=>300
)
'a2'=>array(
'gen2'=>100
'gen3'=>800
)
I have tried this code but not enough, It doesn''t show the duplicate or it's better if it shows the sum of of the value ofduplicate keys
<?php
$array1 = array(a1=>array(200,300,300), a2=>array(100,600,200));
$array2 = array(a1=>array('gen','gen2','gen'), a2=>array('gen2','gen3','gen3'));
$result = array();
foreach($array1 as $k => $v) {
$result[$k] = array_combine($array2[$k], $v);
}
print_r($result);
?>
Thanks you very much for your help
$array1 = array(
'a1' => array(200,300,300),
'a2' => array(100,600,200));
$array2 = array(
'a1' => array('gen','gen2','gen'),
'a2' => array('gen2','gen3','gen3'));
$result = array('a1' => array(), 'a2' => array());
foreach($array2 as $k => $v) {
foreach ($v as $k2 => $v2){
if (array_key_exists($v2, $result[$k])){
$result[$k][$v2] += $array1[$k][$k2];
} else {
$result[$k][$v2] = $array1[$k][$k2];
}
}
}
Output:
Array
(
[a1] => Array
(
[gen] => 500
[gen2] => 300
)
[a2] => Array
(
[gen2] => 100
[gen3] => 800
)
)
This is an interesting situation which I created a working function for, but wondering if I just anyone had any simpler methods for this.
I have the following multidimensional array:
$foo = array(
[0] => array(
'keys' => array(
'key1' => 1,
'key2' => a,
'key3' => 123
),
'values' => array(
//goodies in here
)
)
[1] => array(
'keys' => array(
'key1' => 1,
'key2' => b,
'key3' => 456
),
'values' => array(
//goodies in here
)
)
)
What I wanted, was to transform this into a multidimensional array nested based on the values from the keys array, the output I was looking for is:
$bar = array(
[1] => array(
[a] => array(
[123] => array( //values array from above )
),
[b] => array(
[456] => array( //values array from above )
)
)
)
The keys can always be nested based on their position in the keys array, but the keys themselve are not always the same, keys handles a user defined grouping, so the order and values can change. I also didn't want duplicate keys.
array_merge failed me because in a lot of cases, the array keys are actually numeric ids. So, this function works - but I'm wondering if I made myself a new pair of gloves.
protected function convertAssociativeToMulti( &$output, $keys, $value )
{
$temp = array();
$v = array_values( $keys );
$s = sizeof( $v );
for( $x = 0; $x < $s; $x++ )
{
$k = $v[ $x ];
if ( $x == 0 )
{
if ( !array_key_exists( $k, $output ) )
$output[ $k ] = array();
$temp =& $output[ $k ];
}
if ( $x && ( $x + 1 ) !== $s )
{
if( !array_key_exists( $k, $temp ) )
$temp[ $k ] = array();
$temp =& $temp[$k];
}
if ( ( $x + 1 ) == $s )
$temp[$k] = $value;
}
}
$baz = array();
foreach( $foo as $bar )
{
$this->convertAssociativeToMulti( $baz, $bar['keys'], $bar['values'] );
}
So, how do you do this more simply / refactor what I have?
This is a bit more concise (See it in action here):
$bar=array();
foreach($foo as $item)
{
$out=&$bar;
foreach($item['keys'] as $key)
{
if(!isset($out[$key])) $out[$key]=array();
$out=&$out[$key];
}
foreach($item['values'] as $k=>$v) $out[$k]=$v;
// $out=array_merge($out,$item['values']); -- edit - fixed array_merge
}
var_dump($bar);