I try to sort a multidimensional array in the way, so that the elements with the same value should not being reordered.
This is the given array, which should be sorted by the value of type:
$arr = array(
"a" => array(
"type" => 1
),
"d" => array(
"type" => 1
),
"super" => array(
"type" => 2
),
"c" => array(
"type" => 1
),
"b" => array(
"type" => 1
)
);
The sorted array should be look like this:
Array
(
[super] => Array
(
[type] => 2
)
[a] => Array
(
[type] => 1
)
[d] => Array
(
[type] => 1
)
[c] => Array
(
[type] => 1
)
[b] => Array
(
[type] => 1
)
)
I want to improve your own answer to exclude inefficient array_search(). It is better to index array items before sorting, and use it for equal types.
$index = 0;
foreach ($arr as $key => $value) {
$arr[$key]['index'] = $index;
$index++;
}
uasort($arr, function($a, $b) {
if ($a['type'] < $b['type']) {
return 1;
} elseif ($a['type'] > $b['type']) {
return -1;
} else {
return $a['index'] - $b['index'];
}
});
foreach ($arr as $key => $value) {
unset($arr[$key]['index']);
}
Try a uasort: If you are still on PHP 5.2 or earlier, you'll have to define a sorting function first:
$myArray = array(
"a" => array(
"type" => 1
),
"d" => array(
"type" => 1
),
"super" => array(
"type" => 2
),
"c" => array(
"type" => 1
),
"b" => array(
"type" => 1
)
);
function sortByOrder($a, $b)
{
return $b['type'] - $a['type'];
}
uasort($myArray, 'sortByOrder');
print_r($myArray);
Starting in PHP 5.3, you can use an anonymous function:
uasort($myArray, function ($a, $b) {
return $b['type'] - $a['type'];
});
And finally with PHP 7 you can use the "spaceship operator":
uasort($myArray, function ($a, $b) {
return $b['type'] <=> $a['type'];
});
Output:
Array
(
[super] => Array
(
[type] => 2
)
[b] => Array
(
[type] => 1
)
[c] => Array
(
[type] => 1
)
[a] => Array
(
[type] => 1
)
[d] => Array
(
[type] => 1
)
)
After browsing through the post (How can I sort arrays and data in PHP?)[How can I sort arrays and data in PHP?, I found a solution for my problem.
If the types are equal, I sort the elements into a static order, which I get from a second value id.
Array to sort:
$array = array(
"a" => array(
"id" => "a",
"type" => 1
),
"c" => array(
"id" => "c",
"type" => 1
),
"super" => array(
"id" => "super",
"type" => 2
),
"b" => array(
"id" => "b",
"type" => 1
)
);
Script:
$sort_keys = array_column($array, "id");
function cmp($a, $b){
global $sort_keys;
if ($a["type"] < $b["type"]) {
return 1;
} else if ($a["type"] > $b["type"]) {
return -1;
} else {
return array_search($a["_id"], $sort_keys) - array_search($b["_id"], $sort_keys);
}
}
uasort($array, 'cmp');
I do have the field id in my script already, so I don’t even have to change my array.
Thanks to all who contribute to this post!
Related
I have an array like this
Array
(
[id] => 3
[type] => default
[place] => 1
)
Array
(
[id] => 3
[type] => default
[place] => 2
)
Array
(
[id] => 3
[type] => default
[place] => 3
)
This array is created from this php
for($count=1;$count <= 3;$count++){
$places_array = array(
"id" => "3",
"type" => "default",
"place" => $count,
);
}
Now I want to change the result of this array if the place is found by the php mysql data. For example I have this array.
Array
(
[id] => 7
[type] => 1
[place] => 2
[description] => This is item place 2
[image] => this_is_the_image.png
)
As you can see that the second array is in "place 2". Now I want the result be like this
Array
(
[id] => 3
[type] => default
[place] => 1
)
Array
(
[id] => 7
[type] => 1
[place] => 2
[description] => This is item place 2
[image] => this_is_the_image.png
)
Array
(
[id] => 3
[type] => default
[place] => 3
)
How to achieve this? I have already done with array_search function but no luck.
anyone please help me
=======================EDIT FULL CODE================================
Here is the code, I'm showing the data from database and call it in while loop function
for($count=1;$count <= $max_places;$count++){
$array[] = array(
"id" => $res['id'],
"type" => "default",
"place" => $count
);
while($arr = $stmts->fetch()){
$key = array_search($arr['place'], array_column($array, 'place'));
if($key && array_key_exists($key, $array)) {
$array[$key] = [
"id" => $arr['id'],
"type" => $arr['type'],
"place" => $arr['place'],
"url" => $arr['url'],
"image" => $arr['image']
];
}
}
}
=========================SWAPPED CODE==============================
while($arr = $stmts->fetch()){
$array[] = [
"id" => $arr['id'],
"type" => $arr['type'],
"place" => $arr['place'],
"url" => $arr['url'],
"image" => $arr['image']
];
for($count=1;$count <= $max_places;$count++){
$key = array_search($arr['place'], array_column($array, 'place'));
if($key && array_key_exists($key, $array)) {
$array[] = array(
"id" => $res['id'],
"type" => "default",
"place" => $count
);
}
}
}
You can use the built in
array_multisort()
function.
Example copied from php.net
A nice way to do sorting of a key on a multi-dimensional array without having to know what keys you have in the array first:
<?php
$people = array(
array("name"=>"Bob","age"=>8,"colour"=>"red"),
array("name"=>"Greg","age"=>12,"colour"=>"blue"),
array("name"=>"Andy","age"=>5,"colour"=>"purple")
);
var_dump($people);
$sortArray = array();
foreach($people as $person){
foreach($person as $key=>$value){
if(!isset($sortArray[$key])){
$sortArray[$key] = array();
}
$sortArray[$key][] = $value;
}
}
$orderby = "name"; //change this to whatever key you want from the array
array_multisort($sortArray[$orderby],SORT_DESC,$people);
var_dump($people);
?>
There's no checking on whether your array keys exist, or the array data you are searching on is actually there, but easy enough to add.
Check out https://www.php.net/manual/de/function.ksort.php (user contributes) and
https://www.php.net/manual/de/function.array-multisort.php
Use array_column() with array_search() to get the array key that needs to be modified. See the following code snippet:
<?php
// Here is trick; get the key of the array using array_column
$key = array_search('2', array_column($array, 'place'));
// If any key found modify the array
if ($key && array_key_exists($key, $array)) {
$array[$key] = [
'id' => 7,
'type' => 1,
'place' => 2,
'description' => 'This is item place 2',
'image' => 'this_is_the_image.png',
];
}
print_r($array);
See the demo
Try :
for($count=1;$count <= 3;$count++){
if(array_search($count,array_column("place",$array_from_db)) continue;
$places_array = array(
"id" => "3",
"type" => "default",
"place" => $count,
);
}
This will skip:
Array
(
[id] => 3
[type] => default
[place] => 2
)
=========== EDIT =============
while($arr = $stmts->fetch())
{
$array[$arr['place']] = [
"id" => $arr['id'],
"type" => $arr['type'],
"place" => $arr['place'],
"url" => $arr['url'],
"image" => $arr['image']
];
}
for($count=1;$count <= $max_places;$count++){
if(!isset($array[$count])){
$array[$count] = array(
"id" => $res['id'],
"type" => "default",
"place" => $count
);
}
}
ksort($array);
Found the answer, thanks for all help.
Here is the trick
first we need to determine the main array like this
for($count=1;$count <= $max_places;$count++){
$array[$count] = array(
"id" => $res['id'],
"type" => "default",
"place" => $count
);
}
Then we need to find which place is not available and show the matches.
while($arr = $stmts->fetch()){
$key = array_search($arr['place'], array_column($array, 'place'));
$key+=1;
if($key && array_key_exists($key, $array)) {
$array[$arr['place']] = [
"id" => $arr['id'],
"type" => $res['type'],
"place" => $arr['place'],
"url" => $arr['url'],
"image" => $arr['image']
];
}
}
The trick is in the
$key+=1;
Because the default key in array is 0.
Hope this can help others
I need to sort a multidimensional array by two values.
For example in the array will be 4 keys.
Array(
Array
(
[0] => 4B642D022980E5EBAA7CF4B6E1CC93769921CB42
[1] => downloading
[2] => Title
[3] => 60
)
Array
(
[0] => 4B642D022980E5EBAA7CF4B6E1CC93769921CB42
[1] => downloading
[2] => Title
[3] => 30
)
Array
(
[0] => 4B642D022980E5EBAA7CF4B6E1CC93769921CB42
[1] => paused
[2] => Title
[3] => 30
)
Array
(
[0] => 4B642D022980E5EBAA7CF4B6E1CC93769921CB42
[1] => completed
[2] => Title
[3] => 100
)
)
Is there a way I can sort the array so that it would sort the arrays with key completed first, then downloading second, then paused third and then also sort the arrays containing downloading and paused from 100 down to 0 by the 3 key?
Desired output would be
Array(
Array
(
[0] => 4B642D022980E5EBAA7CF4B6E1CC93769921CB42
[1] => completed
[2] => Title
[3] => 100
)
Array
(
[0] => 4B642D022980E5EBAA7CF4B6E1CC93769921CB42
[1] => downloading
[2] => Title
[3] => 60
)
Array
(
[0] => 4B642D022980E5EBAA7CF4B6E1CC93769921CB42
[1] => downloading
[2] => Title
[3] => 30
)
Array
(
[0] => 4B642D022980E5EBAA7CF4B6E1CC93769921CB42
[1] => paused
[2] => Title
[3] => 30
)
)
uksort is what you need.
It is a sort that lets you define you own callback function.
This callback function is then used by uksort to reorder the array.
You need to write a function that will sort an array based on two criterias.
The first one is the alphabetical order of the field at indice 1 of your array (which contains the words completed, downloading, ...) and in case of tie you would then use the field at indice 3 of your array and sort in decreasing order.
Finally, you will need to pass the function you created as a parameter to uksort.
Hope it helps ! :)
You need to reformat your array and use array_multisort. It will also make thinks more readable:
<?php $ar = Array(
Array(
"id" => "4B642D022980E5EBAA7CF4B6E1CC93769921CB42",
"status" => "completed",
"title" => "Title",
"rank" => "100",
),
Array
(
"id" => "4B642D022980E5EBAA7CF4B6E1CC93769921CB42",
"status" => "downloading",
"title" => "Title",
"rank" => "60",
),
Array
(
"id" => "4B642D022980E5EBAA7CF4B6E1CC93769921CB42",
"status" => "downloading",
"title" => "Title",
"rank" => "30",
),
Array
(
"id" => "4B642D022980E5EBAA7CF4B6E1CC93769921CB42",
"status" => "paused",
"title" => "Title",
"rank" => "30",
),
);
var_dump($ar);
foreach ($ar as $key => $row) {
$status[$key] = $row['status'];
$rank[$key] = $row['rank'];
}
array_multisort($status, SORT_ASC, $rank, SORT_DESC, $ar);
var_dump($ar);
$array = [
[
'4B642D022980E5EBAA7CF4B6E1CC93769921CB42',
'downloading',
'Title',
'60',
],
[
'4B642D022980E5EBAA7CF4B6E1CC93769921CB42',
'downloading',
'Title',
'30',
],
[
'4B642D022980E5EBAA7CF4B6E1CC93769921CB42',
'paused',
'Title',
'30',
],
[
'4B642D022980E5EBAA7CF4B6E1CC93769921CB42',
'completed',
'Title',
'100',
]
];
usort($array, function($a, $b) {
if ($a[1] == $b[1]) {
if ($a[3] == $b[3]) {
return 0;
}
return ($a[3] > $b[3]) ? -1 : 1;
}
$status = ['completed', 'downloading', 'paused'];
foreach ($status as $st) {
if ($a[1] == $st)
return -1;
if ($b[1] == $st)
return 1;
}
return 0;
});
var_dump($array);
I have an array looking like this:
Array(
['some_first_category'] => Array(
['some_first_name'] => Array(
[0]=>'first#email.com',
[1]=>'second#email.com',
[2]=>'third#email.com',
[3]=>'fourth#email.com' )
['some_second_name'] => Array (
[1]=>'first#email.com',
[2]=>'second#email.com')
['some_third_name'] => Array(
[1]=>'first#email.com',
[2]=>'second#email.com',
[3]=>'third#email.com',
[4]=>'fourth#email.com' )
['some_second_category'] => Array(
['some_first_name'] => Array(
[0]=>'first#email.com' )
['some_second_name'] => Array(
[1]=>'first#email.com',
[2]=>'second#email.com',
[3]=>'third#email.com',
[4]=>'fourth#email.com')
['some_third_name'] => Array(
[1]=>'first#email.com',
[2]=>'second#email.com'))
And I want to sort the array by the number of values of that has the names, In my case I want to become this array:
Array(
['some_first_category'] => Array(
['some_third_name'] => Array(
[1]=>'first#email.com',
[2]=>'second#email.com',
[3]=>'third#email.com',
[4]=>'fourth#email.com' )
['some_first_name'] => Array(
[0]=>'first#email.com',
[1]=>'second#email.com',
[2]=>'third#email.com',
[3]=>'fourth#email.com' )
['some_second_name'] => Array (
[1]=>'first#email.com',
[2]=>'second#email.com')
['some_second_category'] => Array(
['some_second_name'] => Array(
[1]=>'first#email.com',
[2]=>'second#email.com',
[3]=>'third#email.com',
[4]=>'fourth#email.com')
['some_third_name'] => Array(
[1]=>'first#email.com',
[2]=>'second#email.com')
['some_first_name'] => Array(
[0]=>'first#email.com' ))
This means sorting categories by name by the number(count) of values of the names. Someone can help me?
Thanks in advance,
Aäron
All you need is uasort
uasort($list, function ($a, $b) {
$a = count($a);
$b = count($b);
return ($a == $b) ? 0 : (($a < $b) ? -1 : 1);
});
Full Example
$list = Array(
'some_first_category' => Array(
'some_first_name' => Array(
0=>'first#email.com',
1=>'second#email.com',
2=>'third#email.com',
3=>'fourth#email.com' ),
'some_second_name' => Array (
1=>'first#email.com',
2=>'second#email.com'),
'some_third_name' => Array(
1=>'first#email.com',
2=>'second#email.com',
3=>'third#email.com',
4=>'fourth#email.com' )
),
'some_second_category' => Array(
'some_first_name' => Array(
0=>'first#email.com' ),
'some_second_name' => Array(
1=>'first#email.com',
2=>'second#email.com',
3=>'third#email.com',
4=>'fourth#email.com'),
'some_third_name' => Array(
1=>'first#email.com',
2=>'second#email.com'))
);
$list = array_map(function ($v) {
uasort($v, function ($a, $b) {
$a = count($a);
$b = count($b);
return ($a == $b) ? 0 : (($a < $b) ? 1 : - 1);
});
return $v;
}, $list);
print_r($list);
Output
Array
(
[some_first_category] => Array
(
[some_first_name] => Array
(
[0] => first#email.com
[1] => second#email.com
[2] => third#email.com
[3] => fourth#email.com
)
[some_third_name] => Array
(
[1] => first#email.com
[2] => second#email.com
[3] => third#email.com
[4] => fourth#email.com
)
[some_second_name] => Array
(
[1] => first#email.com
[2] => second#email.com
)
)
[some_second_category] => Array
(
[some_second_name] => Array
(
[1] => first#email.com
[2] => second#email.com
[3] => third#email.com
[4] => fourth#email.com
)
[some_third_name] => Array
(
[1] => first#email.com
[2] => second#email.com
)
[some_first_name] => Array
(
[0] => first#email.com
)
)
)
Using uksort:
uksort($yourArray, function($a, $b) { return count($b) - count($a); });
Using array_multisort:
array_multisort(array_map('count', $yourArray), SORT_DESC, $yourArray);
and you can see uasort as well
best of luck :)
You should use usort function. Refer here.
function sort_sub($a,$b)
{
$res= count($b)-count($a);
return $res;
}
usort($array_name,'sort_sub')
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Sort multidimensional array by multiple keys
I am trying to find some way how to sort array by key name, but nothing worked so far. The tricky part for me is to sort array by grouping 3 keys. I have this array.
[0] => Array
(
[id] => 8
[zbo_data] => blah
)
[1] => Array
(
[id] => 6
[szn_data] => blah
)
[2] => Array
(
[id] => 5
[gcz_data] => blah
)
[3] => Array
(
[id] => 3
[gcz_data] => blah
)
[4] => Array
(
[id] => 2
[zbo_data] => blah
)
[5] => Array
(
[id] => 1
[szn_data] => blah
)
And I need to sort it by group of 3 in this order: szn_data, zbo_data, gcz_data but I also need to keep the order of [id] (basically primary order by szn_data, zbo_data, gcz_data, secondary [id]). Is there a solution? Or should I construct array differently to be able to sort it? I am trying to figure this out for over 6 hours. Any help is much appreciated.
My desired output is:
[0] => Array
(
[id] => 6
[szn_data] => blah
)
[1] => Array
(
[id] => 8
[zbo_data] => blah
)
[2] => Array
(
[id] => 5
[gcz_data] => blah
)
[3] => Array
(
[id] => 1
[szn_data] => blah
)
[4] => Array
(
[id] => 2
[zbo_data] => blah
)
[5] => Array
(
[id] => 3
[gcz_data] => blah
)
Use usort and implement your comparison function as you wish. For example:
$result = usort($arr, function($a,$b) {
$keys = array('szn_data', 'zbo_data', 'gcz_data');
foreach ($keys as $key) {
// make sure to add here handling of missing keys
$diff = strcmp($b[$key], $a[$key]);
if ($diff!=0) {
return $diff;
}
}
return $b['id'] - $a['id'];
});
Or like this, for any order from max to the min listed in one array
$arr = array (
array(
'id' => 8,
'zbo_data' => 'blah'
),
array(
'id' => 6,
'szn_data' => 'blah'
),
array(
'id' => 5,
'gcz_data' => 'blah'
),
array(
'id' => 3,
'gcz_data' => 'blah'
),
array(
'id' => 2,
'zbo_data' => 'blah'
),
array(
'id' => 1,
'szn_data' => 'blah'
)
);
usort($arr, "my_func");
var_dump($arr);
function my_func($a, $b)
{
$vars = array('szn_data', 'zbo_data', 'gcz_data'); // order of the keys
$id1 = $a['id']; $id2 = $b['id']; unset($a['id'], $b['id']);
$index1 = array_search(key($a), $vars);
$index2 = array_search(key($b), $vars);
if ($index1 == $index2) {
if ($id1 == $id2) return 0;
return ($id1 < $id2) ? 1 : -1;
}
return ($index1 < $index2) ? -1 : 1;
}
ps:
basically primary order by szn_data, zbo_data, gcz_data, secondary
[id]
It does not correspond to your desired output. Secondary means comparison of id when other keys are the same.
ps: Updated - this code is NOT nice or perfect, but it will give you what you need
$vars = array('szn_data', 'zbo_data', 'gcz_data');
$arr = array (
array(
'id' => 8,
'zbo_data' => 'blah'
),
array(
'id' => 6,
'szn_data' => 'blah'
),
array(
'id' => 5,
'gcz_data' => 'blah'
),
array(
'id' => 3,
'gcz_data' => 'blah'
),
array(
'id' => 2,
'zbo_data' => 'blah'
),
array(
'id' => 1,
'szn_data' => 'blah'
)
);
$temp = array();
$cnt = count($arr);
foreach($arr as $item)
{
foreach($vars as $v)
{
if (isset($item[$v])) { $temp[$v][$item['id']] = $item; break; }
}
}
// sort by id
foreach($vars as $v)
{
krsort($temp[$v]);
$temp[$v] = array_values($temp[$v]);
}
$arr = array(); $i = 0; $j = 0;
$completed = false;
do {
foreach($vars as $v)
{
if ($i++>=$cnt) { $completed = true; break; }
if (isset($temp[$v][$j])) $arr[] = $temp[$v][$j];
}
$j++;
} while (!$completed);
// output
var_dump($arr)
I have an php array like below:
Array (
[0] => Array ( [value] => 5 [label] => Akon )
[1] => Array ( [value] => 6 [label] => Angel )
[2] => Array ( [value] => 7 [label] => Britny )
[3] => Array ( [value] => 9 [label] => Mark Anthony )
[4] => Array ( [value] => 8 [label] => Michel )
[5] => Array ( [value] => 4 [label] => Shaggy )
[6] => Array ( [value] => 3 [label] => Smith )
)
I need this array sort by specific letter. For example, if I sort by this "M" letter array should look like below.
Array (
[3] => Array ( [value] => 9 [label] => Mark Anthony )
[4] => Array ( [value] => 8 [label] => Michel )
[6] => Array ( [value] => 3 [label] => Smith )
[0] => Array ( [value] => 5 [label] => Akon )
[1] => Array ( [value] => 6 [label] => Angel )
[2] => Array ( [value] => 7 [label] => Britny )
[5] => Array ( [value] => 4 [label] => Shaggy )
)
The begging letter should comes to first of array.(here begin with m)
I greatly appreciated your any kind of help. Thank you very much...
Your comparison logic is going to be like this:
if two strings A and B start with the same letter, compare them as usual
if A starts with 'M', A wins
if B starts with 'M', B wins
otherwise, compare as usual
in code
$strings = array('Foo', 'Moo', 'Xuux', 'Me', 'Blah', 'Ma');
$letter = 'M';
usort($strings, function($a, $b) use($letter) {
if($a[0] != $b[0]) {
if($a[0] == $letter) return -1;
if($b[0] == $letter) return +1;
}
return strcmp($a, $b);
});
print_r($strings);
class Cmp {
public $letter;
function __construct( $letter ) { $this->letter = $letter; }
function doCmp( $a, $b ) {
if( $a['label'][0] == $this->letter ) {
if( $b['label'][0] != $this->letter ) return -1;
} else {
if( $b['label'][0] == $this->letter ) return 1;
}
return $a['label'] > $b['label'] ? 1 : -1;
}
}
usort( $arr, array( new Cmp( 'M' ), 'doCmp' ) );
$strings = array (
array ( 'value' => 5, 'label' => 'Akon' ),
array ( 'value' => 6, 'label' => 'Angel' ),
array ( 'value' => 7, 'label' => 'Britny' ),
array ( 'value' => 9, 'label' => 'Mark Anthony' ) ,
array ( 'value' => 8, 'label' => 'Michel' ) ,
array ( 'value' => 4, 'label' => 'Shaggy' ) ,
array ( 'value' => 3, 'label' => 'Smith' )
) ;
var_dump($strings);
$letter = 'm';
usort ($strings, function ($left, $right) {
return ((($posLeft = strpos(strtolower($left['label']), 'm')) === false)
? PHP_INT_MAX
: $posLeft)
- ((($posRight = strpos(strtolower($right['label']), 'm')) === false)
? PHP_INT_MAX
: $posRight);
});
var_dump($strings);
Just compares the position of the letter within the two strings. If the letter is not within one of the strings (strpos() returns false), it assumes an "infinite" index (PHP_INT_MAX),
this is an example i found on php.net that could help you and maintain the index : http://www.php.net/manual/en/function.sort.php#99419
Sort the data by the value based on the comparison reflecting the letter (Demo):
<?php
# the data
$data = array(
0 => array(
'value' => 5,
'label' => 'Akon',
),
1 => array(
'value' => 6,
'label' => 'Angel',
),
2 => array(
'value' => 7,
'label' => 'Britny',
),
3 => array(
'value' => 9,
'label' => 'Mark Anthony',
),
4 => array(
'value' => 8,
'label' => 'Michel',
),
5 => array(
'value' => 4,
'label' => 'Shaggy',
),
6 => array(
'value' => 3,
'label' => 'Smith',
),
);
# the letter
$letter = 'M';
# the value to compare against
$value = function(array $a)
{
$key = 'label';
if (!array_key_exists($key, $a))
{
throw new InvalidArgumentException(sprintf('Key "%s" missing.', $key));
}
return $a[$key];
};
# the comparison
$compare = function($a, $b) use ($letter, $value)
{
$a = $value($a);
$b = $value($b);
if($a[0] != $b[0]) {
if($a[0] === $letter) return -1;
if($b[0] === $letter) return +1;
}
return strcmp($a, $b);
};
# the sort
$sort = function() use ($data, $compare)
{
$r = uasort($data, $compare);
if (!$r)
{
throw new RuntimeException('Sort failed.');
}
return $data;
};
print_r($sort());
Use usort to sort by a function. The function can contain any logic you want to put in, as long as the return value indicates sort order (see link for details).