Fastest way of sorting multidimensional arrays in php - php

Array
(
[0] => Array
(
[t] => 81881
[b] => 99494
)
[1] => Array
(
)
...
...
)
I have a multidimensional array like above.The entries in this array would be ranging upto 20k. I want to sort this array acc. to "t" index without calling any external function. Any suggestions for improving the efficiency.

I doubt there is something faster than array_multisort() http://us2.php.net/array_multisort
UPDATE:
Finding out now, that data is not really multidimensional (it's just a key that's hidden as a val of item in array). It would be probably easier to use something like:
http://php.net/manual/en/function.usort.php
function cmp($a, $b)
{
return $a['t']<=>$b['t'];
}
usort($arr, 'cmp');

Related

sorting array based on child array[0] (unix) value

I need an array sorted by Unix timestamp values. I attempted to use both ksort and krsort before realising that occasionally the timestamp values might be the same (and you cannot have duplicate keys in arrays).
Here's an example array I may be faced with:
$array = array(
[
"unix" => 1556547761, // notice the two duplicate unix values
"random" => 4
],
[
"unix" => 1556547761,
"random" => 2
],
[
"unix" => 1556547769,
"random" => 5
],
[
"unix" => 1556547765, // this should be in the 3rd position
"random" => 9
]
);
So what I'm trying to do is sort them all based on each child arrays unix value, however I cannot figure out how to do so. I have tried countless insane ways (including all other sort functions and many, many for loops) to figure it out - but to no avail.
All help is appreciated.
You can use usort which sort your array by given function
Define function as:
function cmpByUnix($a, $b) {
return $a["unix"] - $b["unix"];
}
And use with: usort($array, "cmpByUnix");
Live example: 3v4l
Notice you can also use asort($array); but this will compare also the "random" field and keep the key - if this what you need then look at Mangesh answer
array_multisort() — Sort multiple or multi-dimensional arrays
array_columns() — Return the values from a single column in the input array
You can use array_multisort() and array_column(), then provide your desired sort order (SORT_ASC or SORT_DESC).
array_multisort(array_column($array, "unix"), SORT_ASC, $array);
Explanation:
In array_multisort(), arrays are sorted by the first array given. You can see we are using array_column($array, "unix"), which means that the second parameter is the order of sorting (ascending or descending) and the third parameter is the original array.
This is the result of array_column($array, "unix"):
Array(
[0] => 1556547761
[1] => 1556547761
[2] => 1556547765
[3] => 1556547769
)
This function sorts an array such that array indices maintain their correlation with the array elements they are associated with. This is used mainly when sorting associative arrays where the actual element order is significant.
Note:If two members compare as equal, their relative order in the sorted array is undefined.
Refer : https://www.php.net/manual/en/function.asort.php
asort($array);
echo "<pre>";
print_r($array);
echo "</pre>";
It will give you the output as
Array
(
[1] => Array
(
[unix] => 1556547761
[random] => 2
)
[0] => Array
(
[unix] => 1556547761
[random] => 4
)
[3] => Array
(
[unix] => 1556547765
[random] => 9
)
[2] => Array
(
[unix] => 1556547769
[random] => 5
)
)
You can keep the array key [1],[0],[3],[2]) as it is Or you can keep it as sequential as per your requirement.

Fast searching approach in multidimensional array

The above searching I want with minimum number of code and with best serach performance.
I want to generate an array from this above array by putting logic like:
ALL "EMA" key values of array should not be allowed to match with "JACKSON" key values. Similarly all "JACKSON" key values of the same array are not allowed to fall in any value of "EMA" key. So the resulting array would be like shown below:
Array
(
[0] => Array
(
[EMA] => A
[JACKSON] => B
)
[2] => Array
(
[EMA] => D
[JACKSON] => E
)
)
I want to know the best approach with lesser code to achieve this. The method I have used seems so lengthy. I want a shorter and robust approach.
I think this might be a solution:
$emas = array();
$jacksons = array();
foreach($array as $element){
$emas[] = $element['EMA'];
$jacksons[] = $element['JACKSON'];
}
//array_intersect returns the common values in the arrays as an array
if(!empty(array_intersect($emas, $jacksons))){
echo 'array is invalid!';
}

How do I reorganize an array in PHP?

I am trying to figure out how to reorganize an array..
I have a multidimensional array(Ill call that original_array) and I would like to take the first array within original_array and set the values as keys in a new array. I also want to take the values of the second array in original_array and make them keys and then set the values of the third array in original_array as the values for those keys.
Here is an example of original_array:
Array (
[id] => Array (
[0] => 1
[1] => 3
)
[reward] => Array (
[0] => Movie
[1] => Trip
)
[cost] => Array (
[0] => 50
[1] => 200
)
)
Basically what I would like to do is look like this:
Array (
[1] => Array (
[Movie] => 50
)
[3] => Array (
[Trip] => 200
)
)
Is there a simple and elegant way to merge these like this?
I have spent hours trying to figure this out using array_merge, array_merge_recursive.. etc. And have search SO far and wide for a similar questions, but I haven't found anything that does what I am after.
I was able to correctly combine the 2nd and 3rd arrays in original_array with array_combine. But, I am at a loss as how to combine that result with the 1st array's values in original_array.
Thanks in advance to any help!
Well, the dirty way would be just use combine array functions like array_combine with the input:
$new_array = array_combine(
$array['id'], // parent keys
// combine chunked combined sub keys :p
array_chunk(array_combine($array['reward'], $array['cost']), 1, true)
);
There may be some incantation of array_*() merging functions that could produce what you're looking for, but it is far easier to just iterate over the original array's [id] sub-array and use its values to create new sub-array keys in a different output array.
// To hold your output
$output = array();
// Iterate the original array's [id] sub-array
foreach ($original['id'] as $idxkey => $newkey) {
// Add a sub-array using $newkey to the output array
$output[$newkey] = array(
// Using the index (not value), retrieve the corresponding reward
// value to use as the new array key
// and corresponding cost to use as the new subarray value
$original['reward'][$idxkey] => $original['cost'][$idxkey]
);
}
Here is a demonstration: https://3v4l.org/2pac3
This should work for you:
First you can get the keys for the main array into a separate variable with array_shift(), which will just remove the first element from your array, which is the array holding the keys.
Then use array_map() to loop through both of your subArrays and use reward as key with the cost values as value and return it in an array. At the end you just have to array_combine() your keys $keys with the new created array.
Code:
<?php
$keys = array_shift($arr);
$result = array_combine($keys, array_map(function($k, $v){
return [$k => $v];
}, $arr["reward"], $arr["cost"]));
print_r($result);
?>
You might wanna take a look at BaseArrayHelper from Yii 2.0 Framework.
Although this file is part of a framework it has only very few dependencies and you should be able to use just this file or parts of it in your code with small modifications.
An example for your use case can be found in the index() method.

Sort a multidimensional array by

I want to sort the following multidimensional array by several keywords - let me explain in a simple way.
this is how the parts in my multidimensional array look like
[template] => Array
(
[0] => Array
(
[KeyA] => 123
[KeyB] => ABC
[KeyC] => #FFFFF
[custom] => Array
(
[0] => Array
(
[value] => bla
[var] => 2
)
[1] => Array
(
[value] => c1
[var] => 5
)
)
)
)
there are tons of multidimensional arrays in that template array and I want them now to sort for example by KeyC (#00000 first prio, #FFFFFF second prio, #333333 third prio) and then by KeyA alphabetic.
How to do that ?
PHP has several functions that deal with sorting arrays and the logic behind array sorting are:
Some sort based on the array keys, whereas others by the values: $array['key'] = 'value';
Whether or not the correlation between the keys and values are maintained after the sort, which may mean the keys are reset numerically (0,1,2 ...)
The order of the sort: alphabetical, low to high (ascending), high to low (descending), numerical, natural, random, or user defined
If any of these sort functions evaluates two members as equal then the order is undefined (the sorting is not stable).
Note: All of these sort functions act directly on the array variable itself, as opposed to returning a new sorted array.
The main functions of sorting are described http://www.php.net/manual/en/array.sorting.php and for creating custom sorting you have to tricks best suitable to yourself.

PHP - how to sort multidimensional array by comparing two different sub array values

Im so tired of finding the way to sort this multidimensional array.
I have tried usort() but it doesnt sort the way I want to. Or just maybe I could not figure out the correct logic to use. usort() seems hard to understand for me.
I wanted to sort my data(example below), by finding first which has the higher value (between keys a and b) for each of the sub arrays. And then the sub array which has the highest value either from its keys a or b will be on top.
For example this array:
Array
(
[0] => Array
(
[a]=>5
[b]=>
[c]=>apple
)
[1] => Array
(
[a]=>5
[b]=>7
[c]=>guava
)
[2] => Array
(
[a]=>6
[b]=>
[c]=>banana
)
[3] => Array
(
[a]=>5
[b]=>
[c]=>avocado
)
)
should be sorted like this:
Array
(
[0] => Array
(
[a]=>5
[b]=>7
[c]=>guava
)
[1] => Array
(
[a]=>6
[b]=>
[c]=>banana
)
[2] => Array
(
[a]=>5
[b]=>
[c]=>apple
)
[3] => Array
(
[a]=>5
[b]=>
[c]=>avocado
)
So how exactly I am able to do this? Im so confused how to use usort. What is the best PHP function for sorting this?
The way usort() works is that it requires a way to compare the elements of the array to each other to decide what comes first. You provide it a function, and it calls that function for each element pair in the input array. If the function returns a negative value, it means the first argument is less than the second argument and should come before it in the sorted array. The opposite is true if it returns a positive value.
Let's say you're comparing two sub-arrays s1 and s2. Using the logic you provided, s1 is "less than" s2 -- that is, s1 should come before s2 -- if max(s1.a,s1.b) > max(s2.a,s2.b). Thus, the sort function should return a negative value if this is true. If you subtract s1's max from s2's max, this should yield the proper result.
Try this:
function sort_function(array $arr1, array $arr2) {
$arr1_val = max($arr1['a'],$arr1['b']);
$arr2_val = max($arr2['a'],$arr2['b']);
return $arr2_val - $arr1_val;
}
usort($arr,sort_function);
Assuming $arr is your array.
Your comparison function:
function cmp($a,$b){
// clean up the keys so they don't cause weird cross-type comparisons
(empty($a['a']) ? $a['a'] = 0 : NULL;
(empty($a['b']) ? $a['b'] = 0 : NULL;
(empty($b['a']) ? $b['a'] = 0 : NULL;
(empty($b['b']) ? $b['b'] = 0 : NULL;
/// figure out the pertinent value to compare
$value_from_a_to_compare = max($a['a'],$a['b']);
$value_from_b_to_compare = max($b['a'],$b['b']);
if($value_from_a_to_compare == $value_from_b_to_compare) {
return 0;
}
if($value_from_a_to_compare > $value_from_b_to_compare) {
return 1;
} else {
return -1;
}
}
Call this from usort
usort($your_array,'cmp');
var_dump($your_array);
There are several methods, including writing the function written by dethtron5000 that would enable you to use usort.
I will describe a different suggestion: create a secondary array, in which you put the highest numbers from the first array and then use array_multisort to sort both, using the values from the secondary array.
$helper = array();
foreach ($data as $value)
{
$helper[] = max($value['a'],$value['b']);
}
array_multisort($helper,$data);

Categories