I have an array of the following structure:
Array ( [0] => Array ( [event] => event1 [Weight] => 2 )
And I am trying to sort by 'Weight'. I have tried this:
function cmp($a, $b) {
if ($a['Weight'] > $b['Weight'] ){
return -1;
} else {
return 1;
}
}
But it isnt sorting by weight. It seems to be how i refer to weight but I am unsure how to do this correctly.
You can sort it like this:
uasort($array, function ($a, $b) {
$c = $a['Weight'];
$d = $b['Weight'];
if ($c == $d){
return 0;
}
else if($c > $d){
return 1;
}
else{
return -1;
}
});
<?php
// Obtain a list of columns
//$data = Your Array
foreach ($data as $key => $row) {
$weight[$key] = $row['Weight'];
}
// Sort the data with volume descending, edition ascending
// Add $data as the last parameter, to sort by the common key
array_multisort($weight, SORT_ASC, $data);
?>
I think your problem must be the function you use to do the actual sorting, Here is a complete example of how to sort in ether ascending or descending order.
$array = array(
array( 'event'=> 'something', 'Weight' => 2),
array( 'event'=> 'something', 'Weight' => 1),
array( 'event'=> 'something', 'Weight' => 10),
array( 'event'=> 'something', 'Weight' => 10),
array( 'event'=> 'something', 'Weight' => 0),
array( 'event'=> 'something', 'Weight' => 1),
array( 'event'=> 'something', 'Weight' => -10),
);
function weightCmp($isAscending = true) {
return function($a, $b) use ($isAscending) {
$diff = $a['Weight'] - $b['Weight'];
return $isAscending ? $diff : $diff * -1;
};
}
usort($array, weightCmp());
var_dump($array);
usort($array, weightCmp(false));
var_dump($array);
Related
I have an array like below,
array(
[!] = array(),
[a] = array(),
[.] = array(),
[n] = array(),
[3] = array(),
[1] = array());
I need to sort this array as,
array(
[a] = array(),
[n] = array(),
[1] = array(),
[3] = array(),
[!] = array(),
[.] = array());
How to do this in php()?
TL;TR
The shortest way (both in terms of code and, after some basic comparisons) is the code I suggest near the "Demo2" link below:
uksort($arr, function($a, $b)
{
if (ctype_alnum("$a") === ctype_alnum("$b"))
return $a > $b;
return "$a" < "$b";
});
You can sort an array using the keys with the ksort function:
ksort($array, SORT_STRING);
The second argument is telling PHP to compare all the keys (including the numeric indexes) as strings (meaning an index like 3 will be treated as if it were '3'). This will give you an array where the keys are in ascending order. The order of the keys you show (all single characters) will be the same as their respective ASCII values (. is 46, a is 97 and so on). Seeing as you want to reverse the order, you'll have to use the array_reverse function:
$array = array_reverse($array, true);
Again, the second argument is telling PHP to preserve the keys, if not, the indexes will be reset, leaving you with a numerically indexed array.
You can skip the array_reverse call quite easily by using the uksortfunction. It works much the same way as ksort, but takes a callback function as a second argument, so you can sort by index, in descending order, too:
uksort($arr, function($a, $b)
{
return "$a" < "$b";//added quotes to convert to strings
});
Demo
You will note that this places the '.' key in front of the '!' key. In fact, if both keys are of the same type (numeric, alpha), it would appear you want to sort them in ascending order, which you can do easily:
uksort($arr, function($a, $b)
{
if (ctype_alnum("$a") === ctype_alnum("$b"))//both are alnums, sort ascending
return $a > $b;//sort ascending
return "$a" < "$b";//else sort descending
});
Demo2
If your PHP version doesn't support anonymous functions, you can define a function and pass its name as second argument, but really: you ought to upgrade:
function sortDesc($a, $b)
{
if (ctype_alnum("$a") === ctype_alnum("$b"))
return $a > $b;
return (string) $a < "$b";//casting is valid, too... both do the same thing
}
uksort($array, 'sortDesc');
// function to sort the array keys with
function compare($a, $b)
{
// Look for [A-z]
if (ctype_alpha($a)) {
if (ctype_alpha($b)) {
return strcasecmp($a, $b);
} else {
return -1;
}
} elseif (ctype_alpha($b)) {
return 1;
}
if (is_int($a)) {
if (is_int($b)) {
return $a > $b;
} else {
return -1;
}
} elseif (is_int($b)) {
return 1;
}
return $a > $b;
}
$a = array(
'!' => array(),
'a' => array(),
'.' => array(),
'n' => array(),
'3' => array(),
'1' => array()
);
// use the function we defined above to sort the array.
uksort($a, "compare");
You can try:
<?php
$arr = array(
'!' => array(),
'a' => array(),
'.' => array(),
'n' => array(),
'3' => array(),
'1' => array(),
'$' => array(),
'8' => array(),
'm' => array(),
'x' => array(),
'c' => array(),
);
function mySort($arr){
$keys = array_keys($arr);
sort($keys);
$result = array();
$temp = array();
foreach($keys as $key){
if(!is_numeric($key) && !ctype_alpha($key)){
$temp[$key] = $arr[$key];
}else{
$result[$key] = $arr[$key];
}
}
foreach($temp as $k => $v){
$result[$k] = $v;
}
return $result;
}
print_r(mySort($arr));
?>
Result:
Array
(
[a] => Array()
[c] => Array()
[m] => Array()
[n] => Array()
[x] => Array()
[1] => Array()
[3] => Array()
[8] => Array()
[!] => Array()
[$] => Array()
[.] => Array()
)
this is problem bellow
$array[] = [
'priority' => 0,
'name' => 'a'
];
$array[] = [
'priority' => 0,
'name' => 'b'
];
$array[] = [
'priority' => 10,
'name' => 'c'
];
$array[] = [
'priority' => 0,
'name' => 'b'
];
function sortByPriority($a, $b){
if ($a['priority'] == $b['priority']) {
return 0;
}
return ($a['priority'] < $b['priority']) ? -1 : 1;
}
var_dump($array);
uasort($array, 'sortByPriority');
var_dump($array);
i expected that only 3rd element will be last, but element with name = 'a' now in 3rd position. why? it must be on 1st place!
UPD:
i expected ordering (a,b,b,c) but i see on screen b,b,a,c
ryan-vincent give me a solution link, thank you
SOLUTION
UPDATE
better solution use a http://en.wikipedia.org/wiki/Schwartzian_transform
//decorate
array_walk( $array,create_function('&$v, $k', '$v = [$v[\'priority\'], $k, $v];'));
//sort
sort($array);
//undecorate
array_walk( $array, create_function('&$v, $k', '$v = $v[2];'));
I can't get this. Why doesn' this work?
$list = array(array('id' => 123), array('id' => 10), array('id' => 1000));
$this->OrderListById($list);
return $list;
public function OrderListById($list){
usort($list, function($a, $b) {return $a['id'] - $b['id'];});
}
This returns
array(
(int) 0 => array(
'id' => (int) 123
),
(int) 1 => array(
'id' => (int) 10
),
(int) 2 => array(
'id' => (int) 1000
)
)
And i was hoping something like more ordered :D
array(
(int) 0 => array(
'id' => (int) 10
),
(int) 1 => array(
'id' => (int) 123
),
(int) 2 => array(
'id' => (int) 1000
)
)
The $list parameter in the OrderListById must be a reference:
public function OrderListById(array &$list)
{
usort($list, function($a, $b) {
return $a['id'] - $b['id'];
});
}
Should work.
As a precaution you could typecast values as you compare them, just in case they are not integers, however, that's something you should check before you sort the array:
return (int) $a['id'] - (int) $b['id'];
return $a['id'] - $b['id'];
1000-123 is more than 123-10.
This should be more like the example, where you do a comparison, not subtraction.
function cmp($a, $b)
{
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
In one line that would be:
usort($list, function($a, $b) {return ($a['id'] == $b['id'] ? 0 : (($a['id'] < $b['id']) ? -1 : 1)); });
(not tested, might be a typo, but that's the jist of it)
Either pass by Reference:
public function OrderListById(&$list){
usort($list, function($a, $b) {return $a['id'] - $b['id'];});
}
or return the sorted list
public function OrderListById($list){
usort($list, function($a, $b) {return $a['id'] - $b['id'];});
return $list;
}
I'm trying to sort a multi-dimensional array by another array, but have so far come up short.
array_multisort seems be working only for real sorting.
Suppose I have these 2 arrays:
$order = array(2,3,1);
$data = array(
array('id' => 1, 'title' => 'whatever'),
array('id' => 2, 'title' => 'whatever'),
array('id' => 3, 'title' => 'whatever')
);
Now I would like to sort my $data array according to the order in my $order array.
This is what I would like the result to be:
$data = array(
array('id' => 2, 'title' => 'whatever'),
array('id' => 3, 'title' => 'whatever')
array('id' => 1, 'title' => 'whatever'),
);
I can accomplish this easily by running a nested loop, but that would not scale well (my array is pretty big, and the arrays have many more fields).
In your example the ids in the $data array are are numbered consecutively and starting at 1. The code I give below assumes this is always the case. If this is not the case, the code does not work.
$result = array();
$index = 0;
foreach ($order as $position) {
$result[$index] = $data[$position - 1];
$index++;
}
At http://codepad.org/YC8w0yHh you can see that it works for your example data.
EDIT
If the assumption mentioned above does not hold, the following code will achieve the same result:
<?php
$data = array(
array('id' => 1, 'title' => 'whatever'),
array('id' => 2, 'title' => 'whatever'),
array('id' => 3, 'title' => 'whatever')
);
$order = array(2,3,1);
$order = array_flip($order);
function cmp($a, $b)
{
global $order;
$posA = $order[$a['id']];
$posB = $order[$b['id']];
if ($posA == $posB) {
return 0;
}
return ($posA < $posB) ? -1 : 1;
}
usort($data, 'cmp');
var_dump($data);
See http://codepad.org/Q7EcTSfs for proof.
By calling array_flip() on the $order array it can be used for position lookup. This is like a hashtable lookup, which is linear in time, or O(n). You cannot do better.
There is no built-in function for this in PHP and i am unable to think of any custom function, which would do this using usort. But array_map is simple enough, imo, so why not use it instead?
$sorted = array_map(function($v) use ($data) {
return $data[$v - 1];
}, $order);
For those of you who want to sort data based on an array with actual IDs, rather than based on an array with indexes like in the accepted answer - you can use the following simple comparison function for the usort:
usort($data, function($a, $b) use ($order) {
$posA = array_search($a['id'], $order);
$posB = array_search($b['id'], $order);
return $posA - $posB;
});
So the following example will work fine and you won't get the Undefined offset notices and an array with null values:
$order = [20, 30, 10];
$data = [
['id' => 10, 'title' => 'Title 1'],
['id' => 20, 'title' => 'Title 2'],
['id' => 30, 'title' => 'Title 3']
];
usort($data, function($a, $b) use ($order) {
$posA = array_search($a['id'], $order);
$posB = array_search($b['id'], $order);
return $posA - $posB;
});
echo '<pre>', var_dump($data), '</pre>';
Output:
array(3) {
[0]=>
array(2) {
["id"]=>
int(20)
["title"]=>
string(7) "Title 2"
}
[1]=>
array(2) {
["id"]=>
int(30)
["title"]=>
string(7) "Title 3"
}
[2]=>
array(2) {
["id"]=>
int(10)
["title"]=>
string(7) "Title 1"
}
}
This would be how I would do. I would use a custom usort function (arr_sort) in conjunction with the $data array.
<?php
$order = array(2,3,1);
$data = array(
array('id' => 1, 'title' => 'whatever'),
array('id' => 2, 'title' => 'whatever'),
array('id' => 3, 'title' => 'whatever')
);
function arr_sort($a,$b){
global $order;
foreach ($order as $key => $value) {
if ($value==$a['id']) {
return 0;
break;
}
if ($value==$b['id']) {
return 1;
break;
}
}
}
usort($data,'arr_sort');
echo "<pre>";
print_r($data);
echo "<pre>";
You could try using a custom sort with usort(). This way you can use the first array to determine the order of the second array.
I have an array as following and I want to order that array by the value of the key "attack". First keys of the arrays (15, 13, 18) are ID of some certain item from database, so I don't want these keys to be changed when the array is sorted. Any help would be greatly appreciated.
This is the array:
$data = array(
'15' => array(
'attack' => '45', 'defence' => '15', 'total' => '10'
),
'13' => array(
'attack' => '25', 'defence' => '15', 'total' => '10'
),
'18' => array(
'attack' => '35', 'defence' => '15', 'total' => '10'
)
);
Use uasort():
This function sorts an array such that array indices maintain their correlation with the array elements they are associated with, using a user-defined comparison function.
This is used mainly when sorting associative arrays where the actual element order is significant.
Example:
function cmp($a, $b) {
if ($a['attack'] == $b['attack']) {
return 0;
}
return ($a['attack'] < $b['attack']) ? -1 : 1;
}
uasort($data, 'cmp');
If the values are always strings, you can also use strcmp() in the cmp() function:
function cmp($a, $b) {
return strcmp($a['attack'], $b['attack']);
}
Update:
To sort in descending order you just have to change the return values:
return ($a['attack'] < $b['attack']) ? 1 : -1;
// ^----^
or to pick up #salathe's proposal:
return $b['attack'] - $a['attack'];
Simply use array_multisort
foreach ($data as $key => $row) {
$attack[$key] = $row['attack'];
}
// Sort the data with attack descending
array_multisort($attack, SORT_DESC, $data);
Hope this helps.
$result = [];
foreach ($data as $key => $value) {
$result[$key] = $value;
asort($result[$key]);
}
print_r($result);
Hope this helps !!!