Rearrange an array by an array of indexes - PHP - php
I have an array of $Percentages1 that I have ordered in descending order using arsort() and then I have taken an array containing the new key order using array_keys() called $keyorder
My question is how do I now rearrange another array $Percentages2 into the same key order as $Percentages1?
Any help will be greatly appreciated, thanks very much!
Edit - Code as requested:
//$Percentages1 before sort for example =
// Array ( [0] => 5.10 [1] => 1.52 [2] => 8.42 [3] => 1.11 [4] => 1.35 )
arsort($Percentages1);
//$Percentages1 after sort =
// Array ( [2] => 8.42 [0] => 5.10 [1] => 1.52 [4] => 1.35 [3] => 1.11 )
$keyorder = array();
//So $keyorder is =
// Array ( [0] => 2 [1] => 0 [2] => 1 [3] => 4 [4] => 3 )
$keyorder = array_keys($Percentages1);
//Now I want to do something here to rearrange a $Percentages2 array
//in the same index order as $keyorder.
//For example from this
// Array ( [0] => 2.50 [1] => 3.52 [2] => 9.42 [3] => 9.81 [4] => 0.35 )
//To...
// Array ( [2] => 9.42 [0] => 2.50 [1] => 3.52 [4] => 0.35 [3] => 9.81 )
If you are not adverse to creating another array variable, the simplest course here is just to loop over $keyorder and append the elements at the corresponding key from $Percentages2 onto a new array;.
// Sorted as you already have it...
$keyorder = array_keys($Percentages1);
// Final array
$output = array();
foreach ($keyorder as $key) {
$output[$key] = $Percentages2[$key];
}
// Don't need the source anymore
unset($Percentages2);
Their key order as appended onto $output will be retained in the final result.
Given your input arrays, this produces
print_r($output);
Array
(
[2] => 9.42
[0] => 2.5
[1] => 3.52
[4] => 0.35
[3] => 9.81
)
You actually don't need to use array_keys(). Following the call to arsort(), you can foreach over the sorted $Percentages1 and sort to $output by key:
// Skip array_keys, and read the sorted array directly
arsort($Percentages1);
foreach ($Percentages1 as $key => $value) {
// Same as before inside the loop
$output[$key] = $Percentages2[$key];
}
Related
Sorting multiple subarrays based on a total count from all sub arrays
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");
How can I get random data from a multidimensional array? [duplicate]
This question already has answers here: multi dimensional array in random order (4 answers) Closed 6 years ago. Is it possible to get random data from an array? See My Array: Array ( [0] => Array ( [0] => My Data [1] => Airport [2] => Md ) [1] => Array ( [0] => Live in fear [1] => Science [2] => Sc ) [2] => Array ( [0] => State History [1] => Government [2] => MP ) [3] => Array ( [0] => Real Estate [1] => Other [2] => Property ) [4] => Array ( [0] => Real State [1] => Not Sure [2] => NoData ) ) I need this type of random output... Array ( [0] => Array ( [0] => My Data [1] => Airport [2] => Md ) [1] => Array ( [0] => Real State [1] => Not Sure [2] => NoData ) [2] => Array ( [0] => My Data [1] => Airport [2] => Md ) [3] => Array ( [0] => State History [1] => Government [2] => MP ) [4] => Array ( [0] => Live in fear [1] => Science [2] => Sc ) )
Try the following shuffle function.Hope it would help you. function shuffle_assoc($list) { if (!is_array($list)) return $list; $keys = array_keys($list); shuffle($keys); $random = array(); foreach ($keys as $key) { $random[] = $list[$key]; } return $random; } $arr = array(); $arr[] = array('id' => 50, 'foo' => 'hello'); $arr[] = array('id' => 17, 'foo' => 'byebye'); $arr[] = array('id' => 19, 'foo' => 'foo'); print_r(shuffle_assoc($arr));
You could simply use shuffle() bool shuffle ( array &$array ) This function shuffles (randomizes the order of the elements in) an array. It uses a pseudo random number generator that is not suitable for cryptographic purposes. shuffle($array); // Shuffles your array keys randomly every time.
shuffle() will be a better option in getting out the random value from multi dimensional array. Reference: http://php.net/manual/en/function.shuffle.php shuffle() Example: The shuffle() function randomizes the order of the elements in the array. This function assigns new keys for the elements in the array. Existing keys will be removed <?php $my_array = array("a"=>"red","b"=>"green","c"=>"blue","d"=>"yellow","e"=>"purple"); shuffle($my_array); print_r($my_array); ?> Output: Array ( [0] => red [1] => yellow [2] => green [3] => blue [4] => purple ) //The Output will keep shuffling if you refresh the browser.
PHP three dimensional array, reset key if second element different
Let say i have this print_r output, this is dynamic and not same each condition Array ( [2] => Array ( [1] => 24 [2] => 23,25 ) [3] => Array ( [3] => 27 [4] => 27,26 [5] => 28,27,26 ) ) As you can see, array element [3] starts from [3][4][5], how do it make it start from [1][2]...[n] if the 2nd element is not same. Ideally what i am looking for is something like Array ( [2] => Array ( [1] => 24 [2] => 23,25 ) [3] => Array ( [1] => 27 [2] => 27,26 [3] => 28,27,26 ) ) How do i achieve that? Thanks
array_values returns the values of an array with new numeric indices: foreach($a as $k => $v) { $a[$k] = array_values($v); } Add conditions if you only want to re-index some of your sub-arrays. Functional approach: $a = array_map(function($v) { return array_values($v); }, $a);
How to process second dimension of an Array based on similar first dimension value?
I am trying to write some php code to process the second dimension's value of an array based on similar values of the first dimension values. Following is the sample output. [0] => Array ( [0] => 1 [1] => 0.091238491238491 ) [1] => Array ( [0] => 2 [1] => 0.2221793635487 ) [2] => Array ( [0] => 2 [1] => 0.10662717512033 ) [3] => Array ( [0] => 4 [1] => 0.44354338998346 ) [4] => Array ( [0] => 6 [1] => 0.2248243559719 ) [5] => Array ( [0] => 6 [1] => 0.31764705882353 ) [6] => Array ( [0] => 6 [1] => 0.15764625384879 ) [7] => Array ( [0] => 6 [1] => 0.19160083160083 ) [8] => Array ( [0] => 12 [1] => 0.31054875069499 ) [9] => Array ( [0] => 12 [1] => 0.10915034227918 ) [10] => Array ( [0] => 15 [1] => 0.32915461266474 ) //...........goes to 46000 elements Now what I want to do is, if the index 0 values of each array is similar then I want to add the index 1's value. So for example, if 0 index values for 4 arrays are same , I want to add index 1 values of all 4 arrays. If there is a unique value on 0th index, dont add it with anything, simply store index 1's value and move on. Thanks very much. Ghanshyam
$added = array(); foreach ($array as $item) { if (isset($added[$item[0]])) { $added[$item[0]] += $item[1]; } else { $added[$item[0]] = $item[1]; } }
$p=0; $temp = $final_prod_ex[0][1]; for($x=0; $x<count($final_prod)-1; $x++){ if($final_prod_ex[$x][0]==$final_prod_ex[$x+1][0]){ $temp = $temp + $final_prod_ex[$x+1][1]; } else{ $ans[$p] = $temp." ".$final_prod_ex[$x][0]; $temp = $final_prod_ex[$x+1][1]; $p++; } } Finally figured it out after a lot of thinking(I'm new to programming)...Array's name is $final_prod_ex. Comment on this if I can make it better. And sorry #deceze. I could not understand your solution. I know you were trying to give the value of one array as an index to another. But what the scenario is, that value isnt like 0,1,2,3,4.... Its like 1,3,5,6,7,10. We are missing numbers in between. Maybe I didnt understand your solution. Correct me if I am wrong. Thanks for all the help.
Array sorting question
So I have an array such as this one: Array ( [-1] => Array ( [3] => 3 [1] => 1 [6] => 6 [7] => 7 [5] => 5 ) ) It also contains some other keys that should not be modified. I'd like to the numbers which are in a second array to come first (in the order of that second array), and then will be the numbers that don't exist in the second array, if any. So for that matter, the second array would be: Array ( [0] => 6 [1] => 5 [2] => 3 ) And the final array should be as follows (please remember, there are some more keys inside of that array that should stay as they are): Array ( [-1] => Array ( [6] => 6 [5] => 5 [3] => 3 [1] => 1 [7] => 7 ) ) Any ideas how that can be done? Thanks!
It's not and shouldn't be termed as sorting but may be this code snippet may help you do what you want to: $a1 = Array ( [-1] => Array ( [3] => 3 [1] => 1 [6] => 6 [7] => 7 [5] => 5 ) ); $a2 = Array ( [0] => 6 [1] => 5 [2] => 3 ); $sorted = getSortedArray($a1[-1] , $array2); function getSortedArray($array1 , $array2){ $temp = Array(); $count = 0; $totalKeys = sizeof($array2); for($i=0;$i<sizeof($array2);$i++){ $temp[i] = $array1[$array2[i]]; unset($array1[$array2[i]]); } while($count!=sizeof($array1)) $temp[$totalKeys++] = $array1[$count++]; return $temp; }
I believe the function you're looking for is called array_multisort(). array_multisort() can be used to sort several arrays at once, or a multi-dimensional array by one or more dimensions.