I have a big array as $orderArr:
$orderArr = array("IZQ", "AOH", "VNP", "ICW", "IOQ", "BXP", "SHH", "EAY", "ZAF", "CUW");
which looks like
Array ( [0] => IZQ [1] => AOH [2] => VNP [3] => ICW [4] => IOQ [5] => BXP [6] => SHH [7] => EAY [8] => ZAF [9] => CUW )
and I have two small arrays as $subArr1 and $subArr2:
$subArr1 = array("VNP", "BXP", "ICW", "IZQ");
$subArr2 = array("ZAF", "IZQ", "AOH");
looks like
Array ( [0] => VNP [1] => BXP [2] => ICW [3] => IZQ )
Array ( [0] => ZAF [1] => IZQ [2] => AOH )
Both small arrays (sub array) own elements belong to the big array.
I want to sort two small arrays according to the order of big array, as following:
Array ( [0] => IZQ [1] => VNP [2] => ICW [3] => BXP )
Array ( [0] => IZQ [1] => AOH [2] => ZAF )
I am looking for the simplest codes to do it in php. Any suggestions are welcome.
Probably the simplest would be to compute the intersection and it will return in the order of the first array:
$subArr1 = array_intersect($orderArr, $subArr1);
That will return with the keys of the first array; if you want to reindex instead:
$subArr1 = array_values(array_intersect($orderArr, $subArr1));
You could use usort to sort based on array position:
usort($subArr1, function ($a, $b) use ($orderArr) {
return (array_search($a, $orderArr) < array_search($b, $orderArr)) ? -1 : 1;
});
var_dump($subArr1);
I have some data which looks like this (reduced)
Array
(
[datasets] => Array
(
[0] => Array
(
[label] => NEW
[backgroundColor] => #37fdfd
[data] => Array
(
[0] => 0
[1] => 0
[2] => 5
[3] => 0
)
)
[1] => Array
(
[label] => Grade A
[backgroundColor] => #76ef76
[data] => Array
(
[0] => 8
[1] => 12
[2] => 11
[3] => 0
)
)
[2] => Array
(
[label] => Grade B
[backgroundColor] => #f9f96d
[data] => Array
(
[0] => 1
[1] => 6
[2] => 5
[3] => 3
)
)
[3] => Array
(
[label] => Grade C
[backgroundColor] => #f3ca36
[data] => Array
(
[0] => 3
[1] => 0
[2] => 1
[3] => 4
)
)
[4] => Array
(
[label] => Grade D
[backgroundColor] => #f3ca36
[data] => Array
(
[0] => 3
[1] => 0
[2] => 1
[3] => 0
)
)
)
[labels] => Array
(
[0] => User 0
[1] => User 1
[2] => User 2
[3] => User 3
)
)
Here is a JSON string of the data (not reduced, numbers may differ slightly)
{"datasets":[{"label":"NEW","backgroundColor":"#37fdfd","data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},{"label":"Grade A","backgroundColor":"#76ef76","data":[9,14,12,0,4,17,13,0,10,0,18,18,12,13,13,4]},{"label":"Grade B","backgroundColor":"#f9f96d","data":[1,6,5,0,6,5,2,0,1,0,2,1,4,3,1,15]},{"label":"Grade C","backgroundColor":"#f3ca36","data":[3,0,1,0,2,0,0,0,0,0,1,1,0,0,0,0]},{"label":"Grade C","backgroundColor":"#f3ca36","data":[3,0,1,0,2,0,0,0,0,0,1,1,0,0,0,0]}],"labels":["User 0","User 1","User 2","User 3","User 4","User 5","User 6","User 7","User 8","User 9","User 10","User 11","User 12","User 13","User 14","User 15"]}
Each dataset has an array of data which has keys that directly relates to a key in the labels array. This is currently sorted in alphabetical order by the label.
This data structure is the structure required for Chart.js, which I am using to display a stacked bar chart on my webpage.
Essentially what I need to accomplish is to sort the data array for every user in the labels array based on the sum of each data set for that user. I also need to sort the labels array to be in the same order.
My original idea on how to achieve this is to create a temporary array, loop through all the data sets and add them to this temporary array in the order necessary, but I got stuck after calculating the total for each user. Here is my attempt:
$return = [];
foreach($calculated['labels'] as $key => &$name) {
$total = 0;
foreach($calculated['datasets'] as $dataset) {
$total += $dataset['data'][$key];
}
echo "$name - $total<br>";
}
How can I sort my data and labels in descending order based on the total for each user from all datasets.
Here is my expected output for the reduced data above
Array
(
[datasets] => Array
(
[0] => Array
(
[label] => NEW
[backgroundColor] => #37fdfd
[data] => Array
(
[2] => 5
[1] => 0
[0] => 0
[3] => 0
)
)
[1] => Array
(
[label] => Grade A
[backgroundColor] => #76ef76
[data] => Array
(
[2] => 11
[1] => 12
[0] => 8
[3] => 0
)
)
[2] => Array
(
[label] => Grade B
[backgroundColor] => #f9f96d
[data] => Array
(
[2] => 5
[1] => 6
[0] => 1
[3] => 3
)
)
[3] => Array
(
[label] => Grade C
[backgroundColor] => #f3ca36
[data] => Array
(
[2] => 1
[1] => 0
[0] => 3
[3] => 4
)
)
[4] => Array
(
[label] => Grade D
[backgroundColor] => #f3ca36
[data] => Array
(
[2] => 1
[1] => 0
[0] => 3
[3] => 0
)
)
)
[labels] => Array
(
[2] => User 2 //23 total across all data sets
[1] => User 1 //18 total across all data sets
[0] => User 0 //15 total across all data sets
[3] => User 3 //7 total across all data sets
)
)
The key in the labels array acts as a unique identifier for each user in each dataset data array.
Notice how each set of data inside of each dataset is in the same order, as is the labels array. Each set should be ordered by the total amount from all sets for each user, not necessarily the highest number in each dataset.
For clarification, each set of data in each dataset contains a list of values, the key for each value is directly related to the key for each user in the labels array. So in my example, we have User 0 who has the key "0". This user has a total of 23 from adding up the values from each dataset with the key "0".
Complete solution:
// get array
$a = json_decode('{"datasets":[{"label":"NEW","backgroundColor":"#37fdfd","data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},{"label":"Grade A","backgroundColor":"#76ef76","data":[9,14,12,0,4,17,13,0,10,0,18,18,12,13,13,4]},{"label":"Grade B","backgroundColor":"#f9f96d","data":[1,6,5,0,6,5,2,0,1,0,2,1,4,3,1,15]},{"label":"Grade C","backgroundColor":"#f3ca36","data":[3,0,1,0,2,0,0,0,0,0,1,1,0,0,0,0]},{"label":"Grade C","backgroundColor":"#f3ca36","data":[3,0,1,0,2,0,0,0,0,0,1,1,0,0,0,0]}],"labels":["User 0","User 1","User 2","User 3","User 4","User 5","User 6","User 7","User 8","User 9","User 10","User 11","User 12","User 13","User 14","User 15"]}', true);
// get array of arrays with `data` key from each data set
$users = array_column($a['datasets'], 'data');
// tricky code to sum arrays
$sums = array_map('array_sum', array_map(null, ...$users));
// sort array with keeping keys
arsort($sums);
// we need flip so as `array_replace` will work as expected
$keys = array_flip(array_keys($sums));
// "sorting" `data` subarrays
foreach ($a['datasets'] as &$item) {
$item['data'] = array_replace($keys, $item['data']);
}
// "sorting" `labels` subarray
$a['labels'] = array_replace($keys, $a['labels']);
// see the result
print_r($a);
Fiddle here https://3v4l.org/a7rPL
I see this task as a perfect candidate for array_multisort(). Your synchronously sorted subarrays don't need to retain their initial keys like in u_mulder's output.
The first parameter must be the array of columnar sums, then the descending sort flag as the second parameter, then the labels subarray as a reference, then the dynamic number of data subarrays as references to the original array.
Code: (Demo)
$params = [[], SORT_DESC, &$array['labels']];
foreach ($array['datasets'] as ['data' => &$data]) {
foreach ($data as $i => $d) {
$params[0][$i] = ($params[0][$i] ?? 0) + $d;
}
$params[] = &$data;
}
array_multisort(...$params);
var_export($array);
This looks like a typical job for map(reduce).sort: map each element to an object with id, so you can preserve "which user this used to be" information, and total, the result of reducing data. Then sort with a custom sort function (a,b) => a.total - b.total.
E.g.
function map_total($user, $pos) {
return array(
"id" => $pos,
"total" => array_sum($user.data)
);
}
function cmp_total($a, $b) {
return $a["total"] - $b["total"];
}
$mapped = array_map("map_total", $thing.dataset, array_keys($thing.dataset));
$sorted = usort($mapped, "cmp_total");
Hi I have below multidimensional arrays -
Array
(
[user_attempts] => 0
[2] => Array
(
[0] => 1
[1] => 4
)
[3] => Array
(
[0] => 32
[1] => 23
)
[4] => Array
(
[0] => asdsa
)
[1] => Array
(
[0] => Earth
)
)
and my second array is like below
Array
(
[1] => Array
(
[0] => Earth
)
[2] => Array
(
[0] => 2
[1] => 3
)
[3] => Array
(
[0] => 32
[1] => 23
)
[4] => Array
(
[0] => asdsa
[1] => asdas
)
)
I need to intersect both multidimensional arrays - so the result would be
Array
(
[1] => Array
(
[0] => Earth
)
[3] => Array
(
[0] => 32
[1] => 23
)
)
Can anyone help me to sort this out.
What I have tried is using array_intersect() but it limits to single array not multidimensional i guess.
PHP comes with a ton of functions already built in, but sometimes you still have to implement things yourself. What you want to do can be easily done by using the existing functions.
The goal is to do the following steps:
Find the keys that exist in both arrays
Loop through the array using these keys
Take the items of both input arrays with each of these keys
Calculate the intersection of those two arrays
Put it into a result array
Here is one way to do this:
function array_intersect_2dim (array $a1, array $a2) {
$keys = array_intersect(array_keys($a1), array_keys($a2));
$return = array();
foreach ($keys as $key) {
$return[$key] = array_intersect($a1[$key], $a2[$key]);
if (sizeof($return[$key]) == 0) {
unset($return[$key]);
}
}
return $return;
}
It works only for two dimensions. If you need more, you have to build a recursive approach, which follows the exact same principle.
To make the easier to compare you can use serialize/unserialize on this one. And then use array_intersect(). Try this example: Sample Output
$array1 = array( 'user_attemps' => 0, 2 => array(1, 4), 3 => array(32, 23), 4 => array('asdsa'), 1 => array('Earth'),);
$array2 = array( 1 => array('Earth'), 2 => array(2, 3), 3 => array(32, 23), 4 => array('asdsa', 'asdas'),);
$result = array_map('unserialize',array_intersect(array_map('serialize', $array1), array_map('serialize', $array2)));
print_r($result);
This question already has answers here:
Combine arrays in PHP [duplicate]
(4 answers)
Closed 10 months ago.
I would like to know how to change the contents from several ARRAYS into new ARRAYS.
I have this 3 vars with a ARRAY each, lets say the first var is $number and it has this array:
Array
(
[0] => 1
[1] => 3
[2] => 9
)
The second var is $item and it has this:
Array
(
[0] => house
[1] => car
[2] => bike
)
And the third is $color and it has this:
Array
(
[0] => red
[1] => white
[2] => black
)
How can I change the contents and create new arrays like this:
Array
(
[0] => 1
[1] => house
[2] => red
)
Array
(
[0] => 3
[1] => car
[2] => white
)
Array
(
[0] => 9
[1] => bike
[2] => black
)
You can use array_map:
<?php
$number = [1,3,9];
$item = ['house','car','bike'];
$color = ['red','white','black'];
$res = array_map(null, $number, $item, $color);
print_r($res);
?>
which will output a single array of arrays that you want:
Array
(
[0] => Array
(
[0] => 1
[1] => house
[2] => red
)
[1] => Array
(
[0] => 3
[1] => car
[2] => white
)
[2] => Array
(
[0] => 9
[1] => bike
[2] => black
)
)
You can make a callback function with array_map() that returns each value together:
$result = array();
function merge_arrays($a,$b,$c){
return array($a,$b,$c);
}
$result = array_map("merge_arrays",$number,$item,$color);
DEMO