I know this question has been asked many times but I have yet to see an array built like this. I have tried some of the numerous examples I have found but none seem to do the trick.
I am editing a PHP program that creates a dropdown list of UPS rates. The functions in this program create an array that is structured like this. I'd like to be able to sort this array on [price].
Array
(
[price] => Array
(
[0] => 617.75
[1] => 632.97
[2] => 782.77
[3] => 597.93
[4] => 337.00
)
[option_value] => Array
(
[0] => 07
[1] => 08
[2] => 54
[3] => 65
[4] => 11
)
[option_name] => Array
(
[0] => WorldWide Express
[1] => WorldWide Expedited
[2] => WorldWide Express Plus
[3] => International Saver
[4] => International Standard
)
)
For ascending, I would try:
array_multisort($array['price'], SORT_ASC, $array['option_value'], $array['option_name']);
To go along with the other answer to restructure the array:
foreach($array['price'] as $key => $value) {
$result[] = array('price'=>$array['price'][$key],
'option_value'=>$array['option_value'][$key],
'option_name'=>$array['option_name'][$key]);
}
array_multisort(array_column($result, 'price'), SORT_ASC, $result);
First, I'd refactor the dataset into something sensible:
$i = 0;
$result = [];
while($i < count($source['price']) ) {
$result[$i] = [
'price' => $source['price'][$i],
'option_value' => $source['option_value'][$i],
'option_name' => $source['option_name'][$i]
];
++$i;
}
Then, sort the result using usort:
function sort_by_price($a, $b) {
if ($a['price'] == $b['price']) {
return 0;
}
return ($a['price'] < $b['price']) ? -1 : 1;
}
usort($result, "sort_by_price");
what will i do is this
$price = $array['price'];
asort($price);
foreach($price as $key=>$val){
echo $val.'='.$array['option_value'][$key].'='.$array['option_name'][$key].'<br />';
}
i used asort to sort the value ASC and to preserve the array key. you can also use arsort to sort array value DESC.
asort: http://php.net/manual/en/function.asort.php
arsort: http://php.net/manual/en/function.arsort.php
<?php
$ar = array(
array("10", 11, 100, 100, "a"),
array( 1, 2, "2", 3, 1)
);
array_multisort($ar[0], SORT_ASC, SORT_STRING,
$ar[1], SORT_NUMERIC, SORT_DESC);
var_dump($ar);
?>
array1_sort_order
The order used to sort the previous array argument. Either SORT_ASC to sort ascendingly or SORT_DESC to sort descendingly.
This argument can be swapped with array1_sort_flags or omitted entirely, in which case SORT_ASC is assumed.
Sorting type flags:
SORT_REGULAR - compare items normally (don't change types)
SORT_NUMERIC - compare items numerically
SORT_STRING - compare items as strings
SORT_LOCALE_STRING - compare items as strings, based on the current locale. It uses the locale, which can be changed using setlocale()
SORT_NATURAL - compare items as strings using "natural ordering" like natsort()
SORT_FLAG_CASE - can be combined (bitwise OR) with SORT_STRING or SORT_NATURAL to sort strings case-insensitively
SRC: Example #2 Sorting multi-dimensional array
Related
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.
Since this question has a long explanation, I'll ask the question, then have the explanation below -- Can you sort a multidimensional array by their internal array key value, or is there a better way to get around sorting key value pairs that will have inevitable duplicates, than just using an array?
I am mostly unfamiliar with using PHP and want to learn how to store data.
The very simple example I made is just two HTML form inputs for a score and a name and a PHP file to handle the input to be stored in a plain .txt file, which was originally written with the pattern
42|John
32|Jane
25|John
I was able to successfully split the data, sort it, add the new inputted values then store it all back in the text file to be displayed somewhere else, using the name as the key and the score as the value.
I did all this only to realize that it would only store sort and display the last value associated with each name (i.e.)
42|John
32|Jane
25|John
would be sorted to
32|Jane
25|John
because you, obviously, can't have two of the same keys in an array, which is something I completely overlooked.
My solution, currently is to have an extra number that is unique to each name/score pair, which I formatted in the text file as
1|42|John
2|32|Jane
3|25|John
I then split them into a multidimensional array using this foreach loop
foreach($arr as $key => $value) {
$lineData = explode("|", $value);
$scores[$lineData[0]] = array($lineData[1] => $lineData[2]);
}
To get this output
Array
(
[1] => Array
(
[42] => John
)
[2] => Array
(
[32] => Jane
)
[3] => Array
(
[25] => John
)
)
which avoids overwriting any duplicate names or scores, but leaves me in a position where I can't (to my knowledge) use arsort() to sort the array in to highest to lowest.
You can use array_multisort for that, in combination with array_column. Because the key values are strings, you need to also convert them to integers, for which you can use array_map("intval", ...):
foreach($arr as $value) {
$result[] = explode("|", $value);
}
array_multisort(array_map("intval", array_column($result, 0)), $result);
After the above code has run, $result will be sorted by the key values:
[
['25', 'John'],
['32', 'Jane'],
['42', 'John']
]
To reverse the order, apply array_reverse to the result.
Alternative
You could also decide to sort the original array without conversion to a 2D array, and sort it with a custom sort callback, using usort and (again) intval:
usort($arr, function ($a, $b) {
return intval($a) - intval($b);
});
Then $arr will be sorted to:
[
'25|John',
'32|Jane',
'42|John'
]
To reverse the order, switch the position of $a and $b in the sort callback function:
return intval($b) - intval($a);
If we make a small change to your foreach iteration like this:
foreach($arr as $key => $value) {
$lineData = explode("|", $value);
$scores[] = array('score' => $lineData[1], 'name' => $lineData[2]);
}
Your array will have:
Array
(
[0] => Array
(
[score] => 42
[name] => John
)
[1] => Array
(
[score] => 32
[name] => Jane
)
[2] => Array
(
[score] => 25
[name] => John
)
)
You can use the uasort function, which takes the array to sort, and an user-defined function to do the sorting. The code would look like this:
function compare($a, $b)
{
if ($b['score'] == $a['score']) {
if ($a['name'] == $b['name']) {
return 0;
} elseif ($a['name'] < $b['name']) {
return -1;
} else {
return 1;
}
} else {
return ($b['score'] - $a['score']);
}
}
print_r($scores);
uasort($scores, 'compare');
print_r($scores);
Which gives the following result:
Array
(
[1] => Array
(
[score] => 32
[name] => Jane
)
[2] => Array
(
[score] => 25
[name] => John
)
[0] => Array
(
[score] => 42
[name] => John
)
)
When you use a user-defined function for the sorting you need to return one of 3 values (0 of the values as equal, -1 if $a < $b, and 1 if $b > $a. In this case we're sorting first by score (descending), then by name (ascending). Since you need to order from highest to lowest score, the comparison is $b against $a, for ascending order is $a against $b. I didn't consider the extra number necessary. If you need it then change this line:
$scores[] = array('score' => $lineData[1], 'name' => $lineData[2]);
To this:
$scores[$lineData[0]] = array('score' => $lineData[1], 'name' => $lineData[2]);
In the following array, I want to change the key order from high to low (so for example the year 2014 data appears first).
print_r($array);
Output:
Array
(
[0] => Array
(
[year] => 2013
[name] => xx
)
[1] => Array
(
[year] => 2014
[name] => xx
)
)
I have tried using rsort, but it returns only "1".
$array = rsort($array);
print_r($array); //1
var_dump($array); //bool(true).
rsort() will only work on single-dimensional arrays. You have a 2-dimensional array, so you will need to use a different function such as usort(), which lets you use user-defined comparison function for sorting:
usort($data, function ($a, $b) {
return $a['year'] < $b['year'];
});
Output:
Array
(
[0] => Array
(
[year] => 2014
[name] => xx
)
[1] => Array
(
[year] => 2013
[name] => xx
)
)
Working demo
change
$array = rsort($array);
print_r($array);
to
rsort($array);
print_r($array);
rsort has return value of boolean, so just simple use it like this:
rsort($array);
And also, rsort is sorting array values in reverse order, not array keys, check the documentation:
http://php.net/manual/en/function.rsort.php
So in reverse order simply just use krsort - Sort an array by key in reverse order:
http://php.net/manual/en/function.krsort.php
So your code:
krsort($array);
usort($array, function($item1, $item2){
if ($item1->year > $item2->year ) return true;
else return false;
})
That´s if you wanted to order by year, if you want to order by keys uksort could be used instead
$final = array(array([0] => 123, [1] => 3, [2] => "true"),
array([0] => 9, [1] => 4, [3] => "false"),
array([0] => 541, [1] => 1, [3] => "false"));
I tried using php's sort function so that the $final array will be sorted from lowest to highest based upon the $final[$i][0] value, but it doesn't seem to work. This is just a quick example for the sake of in simplicity. In the real problem that I'm working with, the arrays that are inside of the $final array range from having as little as 3 elements to as many as 7. Don't know if that has any effect on the problem or not.
That's what PHP's usort function is for:
usort($final, function ($a, $b)
{
return $a[0] < $b[0] ? -1 : 1;
});
See it here in action: http://codepad.viper-7.com/omXxkR
I have the following array:
Array ( [0] => Array
( [name] => Jonah
[age] => 27 )
[1] => Array
( [name] => Bianca
[age] => 32 )
)
Is it possible to sort the sub-array values in [age] into some sort of order, such as lowest to highest or vice versa?
You can do this using usort:
usort($arr, function($a, $b)
{
return $a['age'] - $b['age']; // sorts lowest to highest
});
Swap $a and $b in the function to reverse the ordering.
I think this should be possible with bool usort ( array &$array , callback $cmp_function )
http://php.net/manual/en/function.usort.php
Just define a callback that sorts by the [age] key of the value.
This will work:
$ages = array();
foreach ($array as $value) {
$ages[] = $value;
}
array_multisort($values, SORT_ASC, $array);
Any way is good, but this is the "PHP way":
array_multisort() can be used to sort several arrays at once, or a multi-dimensional array by one or more dimensions.