Sorting an array using PHP's usort method - php

Maybe what I want is 'too' custom and has to be done manually, I thought usort can do it but seems I don't understand it completely. Sorting an array of shows by date in descending order but if date is current year then put those in the beginning of the array:
usort($show, function($a, $b){
$year = (int) date("Y", time());
$a = $a['date'];
$b = $b['date'];
if ($a === $year) return -1;
if ($b === $year) return -1;
if ($a === $b) return 0;
return ($a > $b) ? -1 : 1;
});

If $a is current year and $b is not current year, put $a first.
If $a is not current year and $b is current year, put $b first.
Otherwise just do simple comparison/sorting for $a and $b:
$array = array(
1890,
1725,
2000,
2004,
2015,
2016,
2050,
2156,
2019,
);
usort($array, function ($a, $b) {
$y= date('Y');
if ($a == $y && $b != $y) {
return -1;
} elseif ($a != $y && $b == $y) {
return 1;
}
return $b - $a;
});
var_dump($array);
// output
Array
(
[0] => 2015
[1] => 2156
[2] => 2050
[3] => 2019
[4] => 2016
[5] => 2004
[6] => 2000
[7] => 1890
[8] => 1725
)
LIVE

Related

PHP:: Double sort an array by priority

My goal is to sort an array first by the string length and after that sort it again by character value without changing the priority of the length.
Here is my code:
$arr=array("an","am","alien","i");
usort($arr, function ($a, $b) { return (strlen($a) <=> strlen($b)); });
print_r($arr);
I am getting :
Array ( [0] => i [1] => an [2] => am [3] => alien )
...almost but not there)
You're missing the logic to account for sorting by character value. You can add that logic into your custom sort method:
// if lengths are the same, then sort by value
if (strlen($a) == strlen($b)) {
return $a <=> $b;
}
// otherwise, sort by length
return (strlen($a) <=> strlen($b));
You can combine this into a single line by using a ternary:
return strlen($a) == strlen($b) ? $a <=> $b : strlen($a) <=> strlen($b);
Full example (https://3v4l.org/msISD):
<?php
$arr=array("aa", "az", "an","am", "ba", "by", "alien","i");
usort($arr, function ($a, $b) {
return strlen($a) == strlen($b) ? $a <=> $b : strlen($a) <=> strlen($b);
});
print_r($arr);
outputs:
Array
(
[0] => i
[1] => aa
[2] => am
[3] => an
[4] => az
[5] => ba
[6] => by
[7] => alien
)

How sort date in array form oldest to newest php

I have a problem.
I can't sort date in array from oldest to newest ;/
My array:
$arr = array('2013-02-01','2000-02-01','2016-02-17','0000-00-00','0000-00-00','0000-00-00');
i want output
array(
[0] => '2000-02-01',
[1] => '2013-02-01',
[2] => '2016-02-01',
[3] => '0000-00-00',
[4] => '0000-00-00',
[5] => '0000-00-00',
)
i use own function callback in usort, but this not work ;/
function sortDate($a, $b)
{
if ($a == $b) {
return 0;
} elseif($a == '0000-00-00') {
return 1;
}
return strtotime($a) < strtotime($b) ? 1 : -1;
}
someone has an idea for a solution?
The best sort is:
usort($childs, function ($a, $b) {
if ($a == '0000-00-00')
return 1;
if ($b == '0000-00-00')
return -1;
if ($a == $b)
return 0;
return ($a < $b) ? -1 : 1;
});
This will give the result you want tested in PHP versions 5.3.22 - 5.6.18, but there has been changes in PHP 7 that affect the usort function:
$arr = array('2013-02-01','2000-02-01','2016-02-17','0000-00-00','0000-00-00','0000-00-00');
sort( $arr );
usort( $arr, function( $a, $b )
{
if ( $a === $b ) return 0;
if ( strpos( $b, '0000' ) !== false ) return -1;
return ( $a < $b ) ? -1 : 1;
});
Output:
Array
(
[0] => 2000-02-01
[1] => 2013-02-01
[2] => 2016-02-17
[3] => 0000-00-00
[4] => 0000-00-00
[5] => 0000-00-00
)
Test:
https://3v4l.org/0Tvlm
First, I remove all the zero values from the array, then sort it as needed, and then add zero values back:
$arr = array('2013-02-01','2000-02-01','2016-02-17','0000-00-00','0000-00-00','0000-00-00');
$count = count($arr);
$arr = array_filter($arr, function($v) {
if($v == '0000-00-00') {
return false;
} else {
return true;
}
}, ARRAY_FILTER_USE_BOTH);
$count -= count($arr);
sort($arr);
$arr = array_merge($arr, array_fill(0, $count, '0000-00-00'));
print_r($arr);
This sorts your array as following:
Array
(
[0] => 2000-02-01
[1] => 2013-02-01
[2] => 2016-02-17
[3] => 0000-00-00
[4] => 0000-00-00
[5] => 0000-00-00
)
You have the date comparison backwards. You have:
return strtotime($a) < strtotime($b) ? 1 : -1;
You want:
return strtotime($a) < strtotime($b) ? -1 : 1;
You can use:
return $a < $b ? -1 : 1;

Sorting array keeping even values on top PHP

I have tried sorting the below array to keep the even values on top and in sorted order from asc to desc
$array = array(1,2,3,4,5,6,7,8,9,10);
I tried this to sort the array
usort($array, function($a, $b) {
if ($a % 2 == 0 )
{
return 1 ;
}
else
{
return -1;
}
}
);
I got the output like below
Array
(
[0] => 7
[1] => 9
[2] => 1
[3] => 5
[4] => 3
[5] => 2
[6] => 4
[7] => 6
[8] => 8
[9] => 10
)
And I want the output array to be
Array
(
[0] => 2
[1] => 4
[2] => 6
[3] => 8
[4] => 10
[5] => 1
[6] => 3
[7] => 5
[8] => 7
[9] => 9
)
The even and odd values should be sorted in asc to desc order but keep the even values on top of odd values
usort is not stable. The documentation states:
If two members compare as equal, their relative order in the sorted array is undefined.
So, what you can do is:
usort($array, function($a, $b) {
if ($a % 2 == $b % 2) {
return intval($a - $b);
}
elseif ($a % 2 == 0 )
{
return -1 ;
}
else
{
return 1;
}
}
);
This compares the actual values if both are even or both are odd.
I think you need a somewhat more complex function. Because when you look at it there are different cases to take care of and in every one of them something different must happen:
$a and $b both are even: default numeric comparison
$a and $b both are odd: default numeric comparison
$a is even, $b is odd: $a is always smaller than $b
$a is odd, $b is even: $b is always smaller than $a
And for the implementation see the answer of fab.
A bit lenghty but works fine for me:
$array = array(1,2,3,4,5,6,7,8,9,10);
$even =array();
$odd = array();
foreach ($array as $item) {
if($item%2==0) {
$even[] = $item;
}
else {
$odd[] = $item;
}
}
usort($even);
usort($odd);
$array_sort = array_merge($even,$odd);
print_r($array_sort);
usort($array, function($a, $b) {
if ($a % 2 == $b % 2) {
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
} elseif ($a % 2 == 0) {
return -1 ;
} else {
return 1;
}
}
);
Short and simple way to write it:
<?php
$array = array(1,2,3,4,5,6,7,8,9,10);
usort($array, function($a, $b){
if ($a % 2 == $b % 2) {
return $a - $b;
}
return $a % 2 != 0;
});
print_r($array);
?>
or with a ternary:
<?php
$array = array(1,2,3,4,5,6,7,8,9,10);
usort($array, function($a, $b){
return ($a % 2 == $b % 2) ? ($a - $b) : ($a % 2 != 0);
});
print_r($array);
?>
For the comparison function, first take the difference of the mod 2 values of the two numbers.
It will be -1, 0, or 1. If it's not zero, then one number is even and the other is odd, so you can return that value. (That will sort odds above evens.)
If it is zero, then either both numbers are even or both numbers are odd, and you need to take the difference of the two numbers to break the tie.
A concise way to write this is:
usort($array, function($a, $b) {
return $a % 2 - $b % 2 ?: $a - $b;
});
To sort odd numbers at the beginning instead, swap $a and $b in the first comparison.
return $b % 2 - $a % 2 ?: $a - $b;

Sorting 2-dimensional array in descending order keeping original indexes

I need to sort 2-dimensional array in descending order keeping original indexes:
$arr = array();
for ($i=0; $i<5; $i++) {
$arr[] = array(rand(0,5), rand(10,100));
}
The result must be something like this:
[0] => array(5, 100)
[1] => array(5, 90)
[2] => array(5, 35)
[3] => array(4, 10)
[4] => array(3, 15)
So, firstly, the array is sorted with respect to the 1st column, and, secondly it is sorted with respect to the 2nd column.
The function arsort works with vectors, if I understand it correctly.
How can I solve this task?
see http://docs.php.net/uasort
e.g.
<?php
$arr = array(
'A'=>array(5, 100),
'B'=>array(4, 10),
'C'=>array(5, 35),
'D'=>array(3, 15),
'E'=>array(5, 90)
);
uasort($arr, function($a, $b) {
if ( $a[0] < $b[0] ) return 1;
else if ( $a[0] > $b[0] ) return -1;
else if ( $a[1] < $b[1] ) return 1;
else if ( $a[1] > $b[1] ) return -1;
else return 0;
});
foreach($arr as $k=>$v) {
echo $k,'=', join(', ', $v), "\n";
}
prints
A=5, 100
E=5, 90
C=5, 35
B=4, 10
D=3, 15

Sort multi-dimensional array by child key date?

I have the following array:
[0] => Array
(
[name] => The Name
[description] => description
[date] => Thur, May 5 # 7:00 p.m.
[rating] => PG
[year] => 2011
)
[1] => Array
(
[name] => Name 2
[description] => description 2
[date] => Sun, May 8 # 7:30 p.m.
[rating] => 14A
[year] => 2011
)
There are about 5-10 more parts.
What I'm ultimately wanting to do is to use the date part of the array to group these items by day (I.e., "all items with "date" falling into "May 8" should be grouped as such).
Any idea how I'd go about this? Note that the "date" field is stored as such in DB -- that's not a timestamp converted from date(); or whatever.
Many thanks!
Create your own sort function and call it using usort.
For example (not considering the intricacies of your timestamp format):
function date_sort($a, $b) {
return strcmp($a['date'], $b['date']); //only doing string comparison
}
usort($array, 'date_sort');
To complete date_sort, you'll somehow need to convert the dates to comparable types. Here's a solution which converts them to UNIX timestamps:
function convert_date($time) {
$time = substr($time, strpos($time, ',')+1);
$time = str_replace('#', ',', $time);
$time = str_replace('.', '', $time);
return strtotime($time);
}
function date_sort($a, $b) {
$a = convert_date($a['date']);
$b = convert_date($b['date']);
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
Use #Emil Vikström solution, with strtotime as comparing function
function date_sort($a, $b) {
$a = strtotime($a['date']);
$b = strtotime($b['date']);
return ($a == $b) ? 0 : ($a>$b ? - 1 : 1);
}
usort($array, 'date_sort');
http://fr2.php.net/manual/en/function.strtotime.php should deal with most textual dates written in english.
Try this
$arrArray has array you have specified;
$newArray = array();
foreach($arrArray as $key => $value){
$date1 = substr($value['date'], 0, strpos($value['date'],'#')-1);
$newArray[$date1][] = $value;
}
print_r($newArray);
For grouping your data by date, run this little loop
$sortedArray = array();
foreach($dataListing as $data){
//parse your $date field with an reg exp and transform it into integer with format MMDD
$sortedArray[$dateIntegerFormated][] = $data;
}
ksort($sortedArray);
$sortedArray = array_values($sortedArray);
And you can use usort for sorting by time into each group

Categories