简体   繁体   中英

PHP usort inconsistent results depending on presence of space

Sorting a grid of images by date with the following:

          function cmp($a, $b) {
             return $b['date'] - $a['date'];
          }
          usort($grid,"cmp");

I've noticed that it's unable to handle punctuation in sorting, so for my date values that look like this: 2016:06:13 17:13:40 , I strip the colons to get: 20160613 171340 .

However, I noticed that the times were still somewhat random, so it was clearly unable to handle the spaces. After removing the spaces, though, my data sorts in a VERY bizarre way. Sort results with and without spaces below.

With:

20170825 133343
20160613 171340
20151219 153233
20150411 163251
20150411 170725
20120205 190136
20111208 180809
20111001 233800
20111001 222819
20110724 150029
20101110 223719
20100521 112853
20100521 114000
20100504 202257
20100327 112223
20100327 105112
20090816 212251
20090811 231741
20090725 131010
20090617 190555
20090607 182255
20090607 184101
20090607 185514
20090607 185111
20090607 184348
20090527 200636
20090527 203710
20090522 081743
20090522 083222
20090516 184018
20090516 143153
20090516 180547
20090411 103531
20090411 093849
20090411 101501
20090411 101119
20090326 232539
20090209 145905
20080710 120653
20080626 164258
20080217 171941
20070430 222423
20070418 155014
20070412 133327
20070224 123651
20070218 175937
20070202 183904
20070106 142425
20070106 160924
20061115 182508
20060731 020755
20060602 193725
20060602 195715
20060508 170734
20060508 171000
20060508 173855
20060430 165458
20060430 162952
20060408 175236
20060311 095114
20060305 084042
20060117 184836
20051120 164622
20051120 163444
20051120 182736
20050927 040755
20050614 153925
20050613 191608
20050416 063904
20050307 215826
20031115 213612
20030918 165424
20030916 190106

Without:

20111208180809
20050927040755
20111001233800
20111001222819
20080710120653
20050614153925
20050613191608
20110724150029
20170825133343
20080626164258
20050416063904
20050307215826
20080217171941
20101110223719
20100521114000
20100521112853
20100504202257
20070430222423
20160613171340
20070418155014
20070412133327
20100327112223
20100327105112
20070224123651
20070218175937
20070202183904
20070106160924
20070106142425
20031115213612
20061115182508
20151219153233
20030918165424
20030916190106
20090816212251
20090811231741
20060731020755
20090725131010
20060602195715
20060602193725
20090617190555
20090607185514
20090607185111
20090607184348
20090607184101
20090607182255
20060508173855
20060508171000
20060508170734
20090527203710
20090527200636
20090522083222
20090522081743
20090516184018
20090516180547
20090516143153
20060430165458
20060430162952
20060408175236
20090411103531
20090411101501
20090411101119
20090411093849
20060311095114
20060305084042
20090326232539
20150411170725
20150411163251
20090209145905
20060117184836
20120205190136
20051120182736
20051120164622
20051120163444

I can't fathom why this would affect the sorting in this way.

Your comparison function subtract two strings:

return $b['date'] - $a['date'];

The arithmetic operators convert the operators to numbers in order to be able to use them. The conversion of a string to number uses only the leftmost numeric prefix of the input string. Accordingly, 20070106 142425 and 20070106 160924 are both converted to 20070106 when they are used in numeric context.

Your comparison function decides that these two strings are equal and, in consequence, they can appear in any order in the sorted list.

There are several ways to implement this sorting properly.

  1. You can let the values as text representation of dates and compare them in the comparison function using strcmp() . If the dates are formatted using the Ymd H:i:s format then they can be sorted as strings as well.

     function cmp($a, $b) { return strcmp($a['date'], $b['date']); }
  2. Since you already have code that removes ':' and '-' from the text representation of the dates, change it to also remove ' ' (space character). The resulting strings are then correctly converted to numbers before being subtracted and they sort correctly.

  3. Use the strtotime() function (instead of removing characters) to convert the dates to timestamps. They are numbers, they sort correctly and they also have a meaning .

Compare your dates converting it to timestamp.

function cmp($a, $b) {
    //['date'] should be PHP readable date format.
    return strtotime($b['date']) - strtotime($a['date']);
}

usort($grid,"cmp");

Currently string - string converts your ymd his to integer:

var_dump(
    '20100521 114000',
    (int) '20100521 114000',
    20100521114000,
    '20100521 114000' - '20100521 114005' // Diff is 5 seconds
);

string(15) "20100521 114000"
int(20100521)
int(20100521114000)
int(0)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM