This question already has answers here:
How to GROUP BY and SUM PHP Array? [duplicate]
(2 answers)
Closed 5 months ago.
given this array:
array(40) {
[0]=>
array(10) {
["item"]=>
string(5) "AABBCC"
["quants"]=>
string(1) "1"
}
[1]=>
array(10) {
["item"]=>
string(5) "AABBCC"
["quants"]=>
string(1) "1"
}
[2]=>
array(10) {
["item"]=>
string(5) "SLF02"
["quants"]=>
string(1) "1"
}
[3]=>
array(10) {
["item"]=>
string(5) "SLF02"
["quants"]=>
string(1) "3"
}
}
how without using a foreach do I end up with this output:
array(40) {
[0]=>
array(10) {
["item"]=>
string(5) "AABBCC"
["quants"]=>
string(1) "2"
}
[1]=>
array(10) {
["item"]=>
string(5) "SLF02"
["quants"]=>
string(1) "3"
}
}
are there any array_sum functions to do this with a multidimensional array like this in php?
This is a bad idea, but seemed like a fun challenge to do without a foreach:
$arr =
[
[
"item" =>"AABBCC",
"quants" => "1",
],
[
"item" => "AABBCC",
"quants" => "1",
],
[
"item" => "SLF02",
"quants" => "1",
],
[
"item" => "SLF02",
"quants" => "3",
]
];
$arr = array_values(call_user_func_array("array_merge", array_map(function($i) use ($arr) {
return [$i["item"] => ["item" => $i["item"], "quants" => array_reduce(
array_filter($arr, function($j) use ($i) {
return $j["item"] == $i["item"];
}), function($carry, $item) {
return $carry + $item["quants"];
})
]];
}, $arr)));
var_dump($arr);
/*
array(2) {
[0]=>
array(2) {
["item"]=>
string(6) "AABBCC"
["quants"]=>
int(2)
}
[1]=>
array(2) {
["item"]=>
string(5) "SLF02"
["quants"]=>
int(4)
}
}
*/
Here's my approach:
<?php
$array = array(
array('item'=>'AABBCC','quants'=>1),
array('item'=>'AABBCC','quants'=>1),
array('item'=>'SLF02','quants'=>1),
array('item'=>'SLF02','quants'=>3),
);
$summed_array = array();
foreach($array as $row){
$key = $row['item'];
if(!isset($summed_array[$key])){
$summed_array[$key] = array(
'item' => $row['item'],
'quants' => 0
);
}
$summed_array[$key]['quants'] += $row['quants'];
}
// turn the array back to a 0 based array
$summed_array = array_values($summed_array);
echo '<pre>',print_r($summed_array),'</pre>';
Related
I've got this initial data:
$h = [
'id' => 'h',
'name' => 'H',
'config' => [],
];
$g = [
'id' => 'g',
'name' => 'G',
'config' => [],
];
$f = [
'id' => 'f',
'name' => 'F',
'config' => [
[
['id' => $g['id'], 'quantity' => 1],
],
[
['id' => $h['id'], 'quantity' => 2],
],
],
];
$e = [
'id' => 'e',
'name' => 'E',
'config' => [],
];
$d = [
'id' => 'd',
'name' => 'D',
'config' => [
[
['id' => $e['id'], 'quantity' => 1],
['id' => $f['id'], 'quantity' => 3],
],
],
];
$c = [
'id' => 'c',
'name' => 'C',
'config' => [
[
['id' => $f['id'], 'quantity' => 1],
],
[
['id' => $e['id'], 'quantity' => 1],
],
],
];
$b = [
'id' => 'b',
'name' => 'B',
'config' => [
[
['id' => $c['id'], 'quantity' => 1],
],
],
];
$a = [
'id' => 'a',
'name' => 'A',
'config' => [
[
['id' => $d['id'], 'quantity' => 1],
],
[
['id' => $b['id'], 'quantity' => 1],
],
],
];
I will explain how "config" works:
it's an array of possibilities (OR) => for example from $c we can have $f OR $e
inside these possibilities there's an array of AND =>, for example, from $d we have only one possibility with $e AND $f
when the config is empty, it's a leaf so we can stop
and the tricky part (I think) is that we can have quantity inside each config which means from $f we can have $g once OR $h twice and from $d we have $e once AND $f 3 times
What I want to achieve with my algorithm is having output like this :
$possibilities = [
[
[
'id' => 'a',
...
],
[
'id' => 'b',
'parent' => 'a',
...
],
[
'id' => 'c',
'parent' => 'b',
...
],
[
'id' => 'f',
'parent' => 'c'
]
],
[
[
'id' => 'a',
...
],
[
'id' => 'b',
'parent' => 'a',
...
],
[
'id' => 'c',
'parent' => 'b',
...
],
[
'id' => 'e',
'parent' => 'c'
]
],
[
[
'id' => 'a',
...
],
[
'id' => 'd',
'parent' => 'a',
...
],
[
'id' => 'e',
'parent' => 'd',
...
],
[
'id' => 'f-1',
'parent' => 'd',
...
],
[
'id' => 'f-2',
'parent' => 'd',
...
],
[
'id' => 'f-3',
'parent' => 'd',
...
],
[
'id' => 'g',
'parent' => 'f-1',
...
],
[
'id' => 'g',
'parent' => 'f-2',
...
],
[
'id' => 'g',
'parent' => 'f-3',
...
]
],
...
];
So I want to extract and list any possibility and having the parent node (including its number in case quantity > 1)
So far I've tried something like this :
global $datas;
$datas = compact($a, $b, $c, $d, $e, $f, $g, $h);
function formatTree($tree)
{
if (empty($tree['config'])) {
return [$tree];
}
$config = $tree['config'];
unset($tree['config']);
$tree2 = [$tree];
foreach ($config as $item) {
$sub = formatTree($item);
$tree2 = array_merge($tree2, $sub);
}
return $tree2;
}
function preparePossibilities($item)
{
$possibilities = [];
if (empty($item['config'])) {
return [$item];
}
$config = $item['config'];
unset($item['config']);
foreach ($config as $or) {
$finalOr = [];
foreach ($or as $and) {
for ($i = 0; $i < ($and['quantity'] ?? 1); $i++) {
$finalOr[] = $and;
}
}
$item['config'] = $finalOr;
$possibilities[] = $item;
}
return $possibilities;
}
function are_same($trees)
{
$id = null;
foreach ($trees as $tree) {
$oldId = $id;
$id = $tree[0]['id'];
if (isset($oldId) && $oldId !== $id) {
return false;
}
}
return true;
}
function getAllTrees($id)
{
global $datas;
$data = current(array_filter($datas, static function ($d) use ($id) {
return $d['id'] === $id;
}));
$multiplePossibilities = preparePossibilities($data);
$allTrees = [];
foreach ($multiplePossibilities as $possibility) {
if (empty($possibility['config'])) {
return [$possibility];
}
$config = $possibility['config'];
unset($possibility['config']);
$trees = [];
foreach ($config as $i => $and) {
$subTrees = getAllTrees($and['id']);
foreach ($subTrees as $subTree) {
$trees[$i][] = $subTree;
}
}
$trees = array_values($trees);
if (count($trees) === 1) {
foreach ($trees as $tree) {
foreach ($tree as $t) {
$newP = $possibility;
$newP['config'] = [];
$newP['config'][] = $t;
$allTrees[] = $newP;
}
}
} elseif (are_same($trees)) {
$newP = $possibility;
$newP['config'] = $trees;
$allTrees[] = $newP;
} else {
$newP = $possibility;
$newP['config'] = [];
foreach ($trees as $tree) {
if (count($tree) === 1) {
$newP['config'][] = $tree[0];
} else {
foreach ($tree as $t) {
$p3 = $newP;
$p3['config'][] = $t;
$allTrees[] = $p3;
}
}
}
}
}
return $allTrees;
}
foreach (getAllTrees('a') as $tree) {
var_dump(formatTree($tree));
}
And the output is :
array(5) {
[0]=>
array(2) {
["id"]=>
string(1) "a"
["name"]=>
string(1) "A"
}
[1]=>
array(2) {
["id"]=>
string(1) "d"
["name"]=>
string(1) "D"
}
[2]=>
array(3) {
["id"]=>
string(1) "e"
["name"]=>
string(1) "E"
["config"]=>
array(0) {
}
}
[3]=>
array(2) {
["id"]=>
string(1) "f"
["name"]=>
string(1) "F"
}
[4]=>
array(3) {
["id"]=>
string(1) "g"
["name"]=>
string(1) "G"
["config"]=>
array(0) {
}
}
}
array(6) {
[0]=>
array(2) {
["id"]=>
string(1) "a"
["name"]=>
string(1) "A"
}
[1]=>
array(2) {
["id"]=>
string(1) "d"
["name"]=>
string(1) "D"
}
[2]=>
array(3) {
["id"]=>
string(1) "e"
["name"]=>
string(1) "E"
["config"]=>
array(0) {
}
}
[3]=>
array(2) {
["id"]=>
string(1) "f"
["name"]=>
string(1) "F"
}
[4]=>
array(1) {
[0]=>
array(3) {
["id"]=>
string(1) "h"
["name"]=>
string(1) "H"
["config"]=>
array(0) {
}
}
}
[5]=>
array(1) {
[0]=>
array(3) {
["id"]=>
string(1) "h"
["name"]=>
string(1) "H"
["config"]=>
array(0) {
}
}
}
}
array(5) {
[0]=>
array(2) {
["id"]=>
string(1) "a"
["name"]=>
string(1) "A"
}
[1]=>
array(2) {
["id"]=>
string(1) "d"
["name"]=>
string(1) "D"
}
[2]=>
array(3) {
["id"]=>
string(1) "e"
["name"]=>
string(1) "E"
["config"]=>
array(0) {
}
}
[3]=>
array(2) {
["id"]=>
string(1) "f"
["name"]=>
string(1) "F"
}
[4]=>
array(3) {
["id"]=>
string(1) "g"
["name"]=>
string(1) "G"
["config"]=>
array(0) {
}
}
}
array(6) {
[0]=>
array(2) {
["id"]=>
string(1) "a"
["name"]=>
string(1) "A"
}
[1]=>
array(2) {
["id"]=>
string(1) "d"
["name"]=>
string(1) "D"
}
[2]=>
array(3) {
["id"]=>
string(1) "e"
["name"]=>
string(1) "E"
["config"]=>
array(0) {
}
}
[3]=>
array(2) {
["id"]=>
string(1) "f"
["name"]=>
string(1) "F"
}
[4]=>
array(1) {
[0]=>
array(3) {
["id"]=>
string(1) "h"
["name"]=>
string(1) "H"
["config"]=>
array(0) {
}
}
}
[5]=>
array(1) {
[0]=>
array(3) {
["id"]=>
string(1) "h"
["name"]=>
string(1) "H"
["config"]=>
array(0) {
}
}
}
}
array(5) {
[0]=>
array(2) {
["id"]=>
string(1) "a"
["name"]=>
string(1) "A"
}
[1]=>
array(2) {
["id"]=>
string(1) "d"
["name"]=>
string(1) "D"
}
[2]=>
array(3) {
["id"]=>
string(1) "e"
["name"]=>
string(1) "E"
["config"]=>
array(0) {
}
}
[3]=>
array(2) {
["id"]=>
string(1) "f"
["name"]=>
string(1) "F"
}
[4]=>
array(3) {
["id"]=>
string(1) "g"
["name"]=>
string(1) "G"
["config"]=>
array(0) {
}
}
}
array(6) {
[0]=>
array(2) {
["id"]=>
string(1) "a"
["name"]=>
string(1) "A"
}
[1]=>
array(2) {
["id"]=>
string(1) "d"
["name"]=>
string(1) "D"
}
[2]=>
array(3) {
["id"]=>
string(1) "e"
["name"]=>
string(1) "E"
["config"]=>
array(0) {
}
}
[3]=>
array(2) {
["id"]=>
string(1) "f"
["name"]=>
string(1) "F"
}
[4]=>
array(1) {
[0]=>
array(3) {
["id"]=>
string(1) "h"
["name"]=>
string(1) "H"
["config"]=>
array(0) {
}
}
}
[5]=>
array(1) {
[0]=>
array(3) {
["id"]=>
string(1) "h"
["name"]=>
string(1) "H"
["config"]=>
array(0) {
}
}
}
}
array(5) {
[0]=>
array(2) {
["id"]=>
string(1) "a"
["name"]=>
string(1) "A"
}
[1]=>
array(2) {
["id"]=>
string(1) "b"
["name"]=>
string(1) "B"
}
[2]=>
array(2) {
["id"]=>
string(1) "c"
["name"]=>
string(1) "C"
}
[3]=>
array(2) {
["id"]=>
string(1) "f"
["name"]=>
string(1) "F"
}
[4]=>
array(3) {
["id"]=>
string(1) "g"
["name"]=>
string(1) "G"
["config"]=>
array(0) {
}
}
}
array(6) {
[0]=>
array(2) {
["id"]=>
string(1) "a"
["name"]=>
string(1) "A"
}
[1]=>
array(2) {
["id"]=>
string(1) "b"
["name"]=>
string(1) "B"
}
[2]=>
array(2) {
["id"]=>
string(1) "c"
["name"]=>
string(1) "C"
}
[3]=>
array(2) {
["id"]=>
string(1) "f"
["name"]=>
string(1) "F"
}
[4]=>
array(1) {
[0]=>
array(3) {
["id"]=>
string(1) "h"
["name"]=>
string(1) "H"
["config"]=>
array(0) {
}
}
}
[5]=>
array(1) {
[0]=>
array(3) {
["id"]=>
string(1) "h"
["name"]=>
string(1) "H"
["config"]=>
array(0) {
}
}
}
}
array(4) {
[0]=>
array(2) {
["id"]=>
string(1) "a"
["name"]=>
string(1) "A"
}
[1]=>
array(2) {
["id"]=>
string(1) "b"
["name"]=>
string(1) "B"
}
[2]=>
array(2) {
["id"]=>
string(1) "c"
["name"]=>
string(1) "C"
}
[3]=>
array(3) {
["id"]=>
string(1) "e"
["name"]=>
string(1) "E"
["config"]=>
array(0) {
}
}
}
I need to convert simple array to nested array according to specific rules. I've achived it but I'm looking for better solution.
SIMPLE:
array(4) {
[0]=>
array(2) {
["id"]=>
string(2) "11"
["type"]=>
int(3)
}
[1]=>
array(2) {
["id"]=>
string(2) "10"
["type"]=>
int(2)
}
[2]=>
array(2) {
["id"]=>
string(1) "1"
["type"]=>
int(1)
}
[3]=>
array(2) {
["id"]=>
string(1) "0"
["type"]=>
int(1)
}
}
EXPECTED EFFECT:
array(1) {
[0]=>
array(2) {
["type"]=>
int(1)
["child"]=>
array(1) {
[1]=>
array(2) {
["type"]=>
int(1)
["child"]=>
array(1) {
[10]=>
array(2) {
["type"]=>
int(2)
["child"]=>
array(1) {
[11]=>
array(2) {
["type"]=>
int(3)
["child"]=>
array(0) {
}
}
}
}
}
}
}
}
}
MY SOLUTION (not very satisfying):
$nestedArray = [];
foreach ($simpleArray as $item)
{
if (!empty($nestedArray))
{
$array = $nestedArray;
reset($array);
$firstKey = key($array);
}
$nestedArray[$item['id']]['child'] = $nestedArray;
$nestedArray[$item['id']]['type'] = $item['type'];
if (!empty($firstKey))
{
unset($nestedArray[$firstKey]);
}
}
As I said, I'm looking for more elegant way to achieve that. Rule are very simply: every next item is child of previous.
You could use recursion:
function nest($arr) {
return count($arr) ? ["type" => array_pop($arr)["type"], "child" => nest($arr)] : [];
}
With your example input, it would look like this:
$simpleArray = [
["id" => "11", "type" => 3],
["id" => "10", "type" => 2],
["id" => "1", "type" => 1],
["id" => "0", "type" => 1]
];
function nest($arr) {
return count($arr) ? ["type" => array_pop($arr)["type"], "child" => nest($arr)] : [];
}
$nested = nest($simpleArray));
$nested will have the following value:
[
"type" => 1,
"child" => [
"type" => 1,
"child" => [
"type" => 2,
"child" => [
"type" => 3,
"child" => []
]
]
]
]
Don't know this question is asked before or not, cannot find after lot of searching.
My array looks like this,
array(3) {
[0]=>
array(2) {
[0]=>
array(1) {
["userId"]=>
string(3) "421"
}
[1]=>
array(1) {
["userId"]=>
string(3) "329"
}
}
[1]=>
array(1) {
[0]=>
array(1) {
["userId"]=>
string(3) "329"
}
}
[4]=>
array(2) {
[0]=>
array(1) {
["userId"]=>
string(3) "329"
}
[1]=>
array(1) {
["userId"]=>
string(3) "421"
}
}
}
What I want is,
array(1) {
[0]=>
array(5) {
[0]=>
array(1) {
["userId"]=>
string(3) "421"
}
[1]=>
array(1) {
["userId"]=>
string(3) "329"
}
[2]=>
array(1) {
["userId"]=>
string(3) "329"
}
[3]=>
array(1) {
["userId"]=>
string(3) "329"
}
[4]=>
array(1) {
["userId"]=>
string(3) "421"
}
}
}
I have tried with array_merge, array_combine and a lot of foreach() loops. But didn't get luck for desired output.
Don't know how to do this. Please help.
You can flatten your array like this:
$arr = array(array(['user' => 1], ['user' => 2]), ['user' => 3]);
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr));
foreach($iterator as $val) {
$flattened_arr[0][] = $val;
}
var_dump($flattened_arr);
UPDATE: If you don't want to use RecursiveIteratorIterator, the you can also do it like this using array_walk_recursive():
$non_flat_arr = array(array(['user' => 1], ['user' => 2]), ['user' => 3]);
$objTmp = (object) array('flat_arr' => array());
array_walk_recursive($non_flat_arr, create_function('&$v, $k, &$t', '$t->flat_arr[] = $v;'), $objTmp);
var_dump([ 0 => $objTmp->flat_arr]);
This will give you the output as:
array:1 [
0 => array:3 [
0 => 1
1 => 2
2 => 3
]
]
Hope this helps!
This is how my array looks like:
array(3) {
[0]=>
string(3) "600"
[1]=>
string(3) "601"
[2]=>
string(3) "603"
}
This is how my object looks like:
array(7) {
[0]=>
object(stdClass)#688 (6) {
["id"]=>
string(3) "601"
["name"]=>
string(10) "test8opkpo"
["avatar"]=>
string(85) "http://avatars/user/medium.png"
["url"]=>
string(86) "/index.php"
["isOnline"]=>
int(0)
["lastseen"]=>
string(11) "2 weeks ago"
}
[1]=>
object(stdClass)#689 (6) {
["id"]=>
string(3) "604"
["name"]=>
string(6) "nopita"
["avatar"]=>
string(85) "http://avatars/user/medium.png"
["url"]=>
string(82) "/index.php"
["isOnline"]=>
int(0)
["lastseen"]=>
string(10) "1 week ago"
}
[2]=>
object(stdClass)#690 (6) {
["id"]=>
string(3) "603"
["name"]=>
string(6) "test_b"
["avatar"]=>
string(85) "http://avatars/user/medium.png"
["url"]=>
string(82) "/index.php"
["isOnline"]=>
int(0)
["lastseen"]=>
string(11) "6 hours ago"
}
Now I want to remove from the object, each item's id that matches the value inside the array.
So final output of the object should not contain id's that present in the array given. How to do that?
I tried using array_diff_key and unset to no avail.
$contactArray[$i] represent each id in the object
if (in_array($contactArray[$i], $array)) {
$a = array_diff_key($results->contacts, [$i => $contactArray[$i]]);
}
I created my own set of examples to simulate what you want to happen on your array:
$x = array('600','601', '603');
$y = array(
array("id" => "600",
"name" => "test",
"avatar" => "image"
),
array("id" => "601",
"name" => "test1",
"avatar" => "image1"
),
array("id" => "602",
"name" => "test2",
"avatar" => "image2"
),
array("id" => "603",
"name" => "test3",
"avatar" => "image3"
),
array("id" => "604",
"name" => "test4",
"avatar" => "image4"
)
);
echo '<pre>';
var_dump($y);
echo '</pre>';
$new_arr_ = array();
for($i = 0, $ctr = count($y); $i < $ctr; $i++) {
if(!in_array($y[$i]["id"], $x)) {
$new_arr_[] = array($y[$i]["id"], $y[$i]["name"], $y[$i]["avatar"]);
}
}
echo '<pre>';
var_dump($new_arr_);
echo '</pre>';
Hope it helps.
If I understand you correctly the following should work:
$contactArray = array_filter($contactArray, function ($v) use ($array) {
return !in_array(isset($v->id)?$v->id:null, $array);
});
array(
[0]=> array(3)
{
[0]=> array(3)
{
["name"]=> string(1) "a" ,
["code"]=> string(3) "416" ,
["id"]=> string(2) "a1" ,
},
[1]=> array(3)
{
["name"]=> string(1) "a",
["code"]=> string(3) "522" ,
["id"]=> string(2) "a2",
},
[2]=> array(3)
{
["name"]=> string(1) "b" ,
["code"]=> string(3) "580" ,
["id"]=> string(2) "b1" ,
}
},
[1]=> array(3)
{
[0]=> array(3)
{
["name"]=> string(1) "a" ,
["code"]=> string(3) "416" ,
["id"]=> string(2) "a1" ,
},
[1]=> array(3)
{
["name"]=> string(1) "a" ,
["code"]=> string(3) "522" ,
["id"]=> string(2) "a2" ,
},
[2]=> array(3)
{
["name"]=> string(1) "b" ,
["code"]=> string(3) "899" ,
["id"]=> string(2) "b2",
}
}
);
I have array like this. All I need is for each array (e.g [0]=>array())
I will search for the arrays inside and get the array['code'] only for array set that has distinct name value.
Example for array[0]: I will get the array[0][2]['code'] because the array set of this particular array[0][2]['code'] has a unique 'name'
Assume in the below code $array is $arr[0] from your example:
$array = array(
array(
"name" => "a",
"code" => "416",
"id" => "a1"
),
array(
"name" => "a",
"code" => "522",
"id" => "a2"
),
array(
"name" => "b",
"code" => "580",
"id" => "b1"
)
);
$counts = array_count_values(
array_map(function (array $entry) { return $entry['name']; }, $array)
// or array_column($array, 'name') in PHP 5.5+
);
$uniqueNames = array_keys(
array_filter($counts, function ($count) { return $count == 1; })
);
$result = array_filter($array, function (array $entry) use ($uniqueNames) {
return in_array($entry['name'], $uniqueNames);
});
Not necessarily the super most efficient method, but straight forward and functional. It filters the array down to the entries where name exists only once. This may or may not fit your definition of "unique", it's rather unclear what variations in the input data you may have.