I am trying to add a multidimensional array somewhere inside another multidimensional array. I have this code example to explain what I try to do and what goes wrong:
$a_base = [
'wop' =>
[
'tik' =>
[
'a' => 190,
'b' => 323,
'c' => 342
],
'tak' =>
[
'a' => 142,
'b' => 654,
'c' => 785
]
],
'wap' =>
[
'top' =>
[
'a' => 564,
'b' => 667,
'c' => 968
],
'top' =>
[
'a' => 603,
'b' => 694,
'c' => 102
]
]
];
$a_addon = [
'tok' =>
[
'a' => 883,
'b' => 993,
'c' => 878
]
];
array_push($a_base['wop'], $a_addon);
var_dump($a_base);
The result is this:
array(2) {
["wop"]=>
array(3) {
["tik"]=>
array(3) {
["a"]=>
int(190)
["b"]=>
int(323)
["c"]=>
int(342)
}
["tak"]=>
array(3) {
["a"]=>
int(142)
["b"]=>
int(654)
["c"]=>
int(785)
}
[0]=>
array(1) {
["tok"]=>
array(3) {
["a"]=>
int(883)
["b"]=>
int(993)
["c"]=>
int(878)
}
}
}
["wap"]=>
array(1) {
["top"]=>
array(3) {
["a"]=>
int(603)
["b"]=>
int(694)
["c"]=>
int(102)
}
}
}
But what I need is this (without the [0]=> array(1) {...}):
array(2) {
["wop"]=>
array(3) {
["tik"]=>
array(3) {
["a"]=>
int(190)
["b"]=>
int(323)
["c"]=>
int(342)
}
["tak"]=>
array(3) {
["a"]=>
int(142)
["b"]=>
int(654)
["c"]=>
int(785)
}
["tok"]=>
array(3) {
["a"]=>
int(883)
["b"]=>
int(993)
["c"]=>
int(878)
}
}
["wap"]=>
array(1) {
["top"]=>
array(3) {
["a"]=>
int(603)
["b"]=>
int(694)
["c"]=>
int(102)
}
}
}
I have tried other functions like array_combine et cetera, but without success. Can anyone help me how to do this?
An array union will work perfectly as a functionless array merging technique on your associative arrays.
Code: (Demo)
$a_base['wop'] += $a_addon;
Use array_merge()
$a_base['wop'] = array_merge($a_base['wop'], $a_addon);
Related
I'm wring a PHP script to group some payment info using date. part of original array is like this.
array(50) {
[0]=>
array(2) {
["Datum"]=>
string(10) "2016-07-07"
["C"]=>
int(1)
}
[1]=>
array(2) {
["Datum"]=>
string(10) "2016-07-07"
["C"]=>
int(1)
}
[2]=>
array(2) {
["Datum"]=>
string(10) "2016-07-07"
["Paypal"]=>
int(1)
}
[3]=>
array(2) {
["Datum"]=>
string(10) "2016-07-07"
["Bank"]=>
int(1)
}
[4]=>
array(2) {
["Datum"]=>
string(10) "2016-07-12"
["C"]=>
int(1)
}
[5]=>
array(2) {
["Datum"]=>
string(10) "2016-06-13"
["C"]=>
int(1)
}
[6]=>
array(2) {
["Datum"]=>
string(10) "2016-06-13"
["C"]=>
int(1)
}
[7]=>
array(2) {
["Datum"]=>
string(10) "2016-06-13"
["Afterpay"]=>
int(1)
}
[8]=>
array(2) {
["Datum"]=>
string(10) "2016-06-13"
["C"]=>
int(1)
}
[9]=>
array(2) {
["Datum"]=>
string(10) "2016-06-13"
["C"]=>
int(1)
}
[10]=>
array(2) {
["Datum"]=>
string(10) "2016-06-12"
["C"]=>
int(1)
}
[11]=>
array(2) {
["Datum"]=>
string(10) "2016-06-13"
["C"]=>
int(1)
}
[12]=>
array(2) {
["Datum"]=>
string(10) "2016-06-13"
["C"]=>
int(1)
}
[13]=>
array(2) {
["Datum"]=>
string(10) "2016-06-13"
["C"]=>
int(1)
}
[14]=>
array(2) {
["Datum"]=>
string(10) "2016-06-13"
["C"]=>
int(1)
}
[15]=>
array(2) {
["Datum"]=>
string(10) "2016-06-13"
["C"]=>
int(1)
}
[16]=>
array(2) {
["Datum"]=>
string(10) "2016-06-13"
["C"]=>
int(1)
}
[17]=>
array(2) {
["Datum"]=>
string(10) "2016-06-13"
["C"]=>
int(1)
}
[18]=>
array(2) {
["Datum"]=>
string(10) "2016-06-14"
["Afterpay"]=>
int(1)
}
[19]=>
array(2) {
["Datum"]=>
string(10) "2016-06-14"
["C"]=>
int(1)
}
}
I wrote some codes to group those by date. here is my code
//$shipment - this is the original array
$array1 = array('C' => null, 'afterpay' => null,'paypal' => null, 'Bank' => null, 'Ideal' => null);
$array2 = array();
array_walk($shipment, function ($v) use (&$array2, $array1) {
$a = $v['Datum'];
if (!isset($array2[$a])) {
$array2[$a] = $array1;
}
unset($v['Datum']);
$array2[$a] = array_merge($array2[$a], $v);
});
Output after grouping
Array
(
[2016-07-07] => Array
(
[C] => 1
[afterpay] =>
[paypal] =>
[Bank] => 1
[Ideal] =>
[Paypal] => 1
)
[2016-07-12] => Array
(
[C] => 1
[afterpay] =>
[paypal] =>
[Bank] =>
[Ideal] =>
)
[2016-06-13] => Array
(
[C] => 1
[afterpay] =>
[paypal] =>
[Bank] =>
[Ideal] =>
[Afterpay] => 1
)
[2016-06-12] => Array
(
[C] => 1
[afterpay] =>
[paypal] =>
[Bank] =>
[Ideal] =>
)
[2016-06-14] => Array
(
[C] => 1
[afterpay] =>
[paypal] =>
[Bank] =>
[Ideal] =>
[Afterpay] => 1
)
)
but it's difficult me to find a way to count the payment method numbers and assign it
Example for 2016-07-07 array should be C= 2,Paypal = 1, Bank = 1
[2016-07-07] => Array
(
[C] => 2
[afterpay] =>
[paypal] =>
[Bank] => 1
[Ideal] =>
[Paypal] => 1
)
can someone help me to add some code for get sum of payment methods and assign, thanks a lot
This happens because array_merge override the data if 2 keys are the same - what you need is to add all fields.
First, change $array1 with init field as 0 instead of null.
Second, in your array_walk, replace $array2[$a] = array_merge($array2[$a], $v); with:
foreach($v as $k => $v)
$array2[$a][$k] += $v;
This way you will add up each category
We need to increase Payment Method instead of merge array, to prevent overwrite old value.
Below code working for me
<?php
$shipment = [
[
'Datum' => '2016-07-07',
'C' => 1,
],
[
'Datum' => '2016-07-07',
'C' => 1,
],
[
'Datum' => '2016-07-07',
'Paypal' => 1,
],
[
'Datum' => '2016-07-07',
'Bank' => 1,
],
[
'Datum' => '2016-07-12',
'Bank' => 1,
],
];
$template = ['C' => 0, 'Afterpay' => 0, 'Paypal' => 0, 'Bank' => 0, 'Ideal' => 0];
$result = [];
array_walk($shipment, function ($v) use (&$result, $template) {
// Init by Datum if it is not in array
$date = $v['Datum'];
if (!isset($result[$date])) {
$result[$date] = $template;
}
// Unset Datum to get final payment method only
unset($v['Datum']);
$itemKey = array_keys($v)[0];
// Increase number
$result[$date][$itemKey] += $v[$itemKey];
});
// Dump result
var_dump($result);
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" => []
]
]
]
]
I have
$products = array(
"product1" => [
"a" => ["total" => 1],
"b" => ["total" => 3],
"c" => ["total" => 2],
],
"product2" => [
"d" => ["total" => 3],
"f" => ["total" => 2],
"e" => ["total" => 1],
],
"product3" => [
"g" => ["total" => 3]
],
);
theses are my products and my stocks for each warehouses (warehouse a has 1 item of product1...)
I want to sort each warehouse by stock for each products.
I've done that :
foreach ($products as &$stocks) {
uasort($stocks, function($elmt1, $elmt2) {
return $elmt2["total"] - $elmt1["total"];
});
}
where I print my new array :
array(3) {
["product1"]=>
array(3) {
["b"]=>
array(1) {
["total"]=>
int(3)
}
["c"]=>
array(1) {
["total"]=>
int(2)
}
["a"]=>
array(1) {
["total"]=>
int(1)
}
}
["product2"]=>
array(3) {
["d"]=>
array(1) {
["total"]=>
int(3)
}
["f"]=>
array(1) {
["total"]=>
int(2)
}
["e"]=>
array(1) {
["total"]=>
int(1)
}
}
["product3"]=>
&array(1) {
["g"]=>
array(1) {
["total"]=>
int(3)
}
}
}
It did my job but when I get a closer look I can see the "&" char in only one of the arrays.
Why ?
Due to the fact that $item - a reference to the last element of the array.
You can do this trick:
$array = ['a', 'b', 'c'];
foreach ($array as &$item) {
}
foreach ($array as $item) {
$item = 1;
}
var_dump($array);
Output:
array(3) {
[0]=>
string(1) "a"
[1]=>
string(1) "b"
[2]=>
&int(1)
}
It's not terrible, as long as you do not start to use $item.
It is better to make a job with reference in different function
$array = ['a', 'b', 'c'];
$test = function () use (&$array) {
foreach ($array as &$item) {
}
};
$test();
var_dump($array);
Output:
array(3) {
[0]=>
string(1) "a"
[1]=>
string(1) "b"
[2]=>
string(1) "c"
}
Or try this:
$products = array(
"product1" => [
"a" => ["total" => 1],
"b" => ["total" => 3],
"c" => ["total" => 2],
],
"product2" => [
"d" => ["total" => 3],
"f" => ["total" => 2],
"e" => ["total" => 1],
],
"product3" => [
"g" => ["total" => 3]
],
);
foreach ($products as $key=>$stocks) {
uasort($products[$key], function($elmt1, $elmt2) {
return $elmt2["total"] - $elmt1["total"];
});
}
var_dump($products);
Output:
array(3) {
["product1"]=>
array(3) {
["b"]=>
array(1) {
["total"]=>
int(3)
}
["c"]=>
array(1) {
["total"]=>
int(2)
}
["a"]=>
array(1) {
["total"]=>
int(1)
}
}
["product2"]=>
array(3) {
["d"]=>
array(1) {
["total"]=>
int(3)
}
["f"]=>
array(1) {
["total"]=>
int(2)
}
["e"]=>
array(1) {
["total"]=>
int(1)
}
}
["product3"]=>
array(1) {
["g"]=>
array(1) {
["total"]=>
int(3)
}
}
}
my php code is:
<?php
$arr = array(
'a' => array(
'name' => 'aaa',
'pos' => 2
),
'b' => array(
'name' => 'bbb',
'pos' => 1
)
);
var_dump($arr);
function func_sort($a, $b) {
return intval($a['pos']) - intval($b['pos']);
}
usort($arr, 'func_sort');
var_dump($arr);
?>
the result is:
array(2) {
["a"]=>
array(2) {
["name"]=>
string(3) "aaa"
["pos"]=>
int(2)
}
["b"]=>
array(2) {
["name"]=>
string(3) "bbb"
["pos"]=>
int(1)
}
}
array(2) {
[0]=>
array(2) {
["name"]=>
string(3) "bbb"
["pos"]=>
int(1)
}
[1]=>
array(2) {
["name"]=>
string(3) "aaa"
["pos"]=>
int(2)
}
}
after usrot,string key change to num key,who can tell me why? and how to sort an array(with string key) but keep string key?
usort() does that: it's the documented behaviour of the function, see the second Note on the docs page
if you need to maintain key associativity, use uasort()
I have this multidimensional array:
$data[] = array('name' => 'Mini 16', 'id' => 105);
$data[] = array('name' => 'Mini 15', 'id' => 5650);
$data[] = array('name' => 'Mini 100', 'id' => 9889);
$data[] = array('name' => 'Mini 20', 'id' => 587);
I want to order the array by name column sorting naturally, but is difficult for me.
The expected result:
[
['name' => 'Mini 15', 'id' => 5650],
['name' => 'Mini 16', 'id' => 105],
['name' => 'Mini 20', 'id' => 587],
['name' => 'Mini 100', 'id' => 9889]
]
You can use usort() to sort the array by a custom function, and use strnatcmp() to do the natural comparison of two strings like so:
usort( $data, function( $el1, $el2) { return strnatcmp( $el1['name'], $el2['name']); });
So before, your array was this:
array(4) {
[0]=>
array(2) {
["name"]=>
string(7) "Mini 16"
["id"]=>
int(105)
}
[1]=>
array(2) {
["name"]=>
string(7) "Mini 15"
["id"]=>
int(5650)
}
[2]=>
array(2) {
["name"]=>
string(8) "Mini 100"
["id"]=>
int(9889)
}
[3]=>
array(2) {
["name"]=>
string(7) "Mini 20"
["id"]=>
int(587)
}
}
And now it looks like:
array(4) {
[0]=>
array(2) {
["name"]=>
string(7) "Mini 15"
["id"]=>
int(5650)
}
[1]=>
array(2) {
["name"]=>
string(7) "Mini 16"
["id"]=>
int(105)
}
[2]=>
array(2) {
["name"]=>
string(7) "Mini 20"
["id"]=>
int(587)
}
[3]=>
array(2) {
["name"]=>
string(8) "Mini 100"
["id"]=>
int(9889)
}
}
Note that for lower versions of PHP, you won't be able to use an anonymous function, and would instead need something like this:
usort( $data, create_function( '$el1, $el2', 'return strnatcmp( $el1[\'name\'], $el2[\'name\']);' ));
If you're using PHP 5.4 or newer, you can use array_multisort with the SORT_NATURAL flag. Just follow Example #3 in the http://php.net/manual/en/function.array-multisort.php documentation, but add the SORT_NATURAL option.
As half-answered by Craig, array_multisort() will be more performant than usort() because array_multisort() doesn't make iterated function calls.
Code: (Demo)
array_multisort(array_column($data, 'name'), SORT_NATURAL, $data);
var_export($data);
This is the modern, arrow-function syntax for nickb's answer.
Code (PHP7.4 and higher): (Demo)
usort($data, fn($a, $b) => strnatcmp($a['name'], $b['name']));
var_export($data);