PHP usort()不准确?

时间:2018-02-21 01:49:02

标签: php usort

我有一个多维数组。在每个数组中,它们是一个名为" elo-rating"的子值。我想根据这个子值对数组进行排序。

所以我接受了名为$newRanks的数组并通过以下方式运行它:

uasort($newRanks, create_function(
    '$b, $a', 'return $a["elo_rating"] - $b["elo_rating"];'
));

运行该代码后,我的数组返回如下:

array:52 [
  "3-1154" => array:4 [
    "league_id" => 3
    "user_id" => 1154
    "elo_matches" => 8
    "elo_rating" => 1224.47797881
  ]
  "3-205" => array:4 [
    "league_id" => 3
    "user_id" => 205
    "elo_matches" => 11
    "elo_rating" => 1207.86593741
  ]
  "3-1" => array:4 [
    "league_id" => 3
    "user_id" => 1
    "elo_matches" => 17
    "elo_rating" => 1206.60264689
  ]
  "3-285" => array:4 [
    "league_id" => 3
    "user_id" => 285
    "elo_matches" => 4
    "elo_rating" => 1187.31524255
  ]
  "3-259" => array:4 [
    "league_id" => 3
    "user_id" => 259
    "elo_matches" => 4
    "elo_rating" => 1173.02391767
  ]
  "3-12689" => array:4 [
    "league_id" => 3
    "user_id" => 12689
    "elo_matches" => 4
    "elo_rating" => 1167.46830619
  ]
  "3-1603" => array:4 [
    "league_id" => 3
    "user_id" => 1603
    "elo_matches" => 13
    "elo_rating" => 1153.3060092
  ]
  "3-16" => array:4 [
    "league_id" => 3
    "user_id" => 16
    "elo_matches" => 7
    "elo_rating" => 1146.65083202
  ]
  "3-1609" => array:4 [
    "league_id" => 3
    "user_id" => 1609
    "elo_matches" => 3
    "elo_rating" => 1122.679103
  ]
  "3-333" => array:4 [
    "league_id" => 3
    "user_id" => 333
    "elo_matches" => 5
    "elo_rating" => 1112.56694511
  ]
  "3-10030" => array:4 [
    "league_id" => 3
    "user_id" => 10030
    "elo_matches" => 4
    "elo_rating" => 1091.27782914
  ]
  "3-378" => array:4 [
    "league_id" => 3
    "user_id" => 378
    "elo_matches" => 9
    "elo_rating" => 1082.0354022
  ]
  "3-6107" => array:4 [
    "league_id" => 3
    "user_id" => 6107
    "elo_matches" => 5
    "elo_rating" => 1059.74850166
  ]
  "3-5179" => array:4 [
    "league_id" => 3
    "user_id" => 5179
    "elo_matches" => 3
    "elo_rating" => 1046.60181418
  ]
  "3-1476" => array:4 [
    "league_id" => 3
    "user_id" => 1476
    "elo_matches" => 9
    "elo_rating" => 1038.88789903
  ]
  "3-70" => array:4 [
    "league_id" => 3
    "user_id" => 70
    "elo_matches" => 8
    "elo_rating" => 1038.63959146
  ]
  "3-303" => array:4 [
    "league_id" => 3
    "user_id" => 303
    "elo_matches" => 7
    "elo_rating" => 1039.26666217
  ]
  "3-59" => array:4 [
    "league_id" => 3
    "user_id" => 59
    "elo_matches" => 1
    "elo_rating" => 1033.78309445
  ]
  "3-1017" => array:4 [
    "league_id" => 3
    "user_id" => 1017
    "elo_matches" => 4
    "elo_rating" => 1002.79264647
  ]
  "3-632" => array:4 [
    "league_id" => 3
    "user_id" => 632
    "elo_matches" => 3
    "elo_rating" => 1002.2039368
  ]
  "3-177" => array:4 [
    "league_id" => 3
    "user_id" => 177
    "elo_matches" => 4
    "elo_rating" => 994.838857477
  ]
  "3-12466" => array:4 [
    "league_id" => 3
    "user_id" => 12466
    "elo_matches" => 4
    "elo_rating" => 994.761652125
  ]
  "3-9725" => array:4 [
    "league_id" => 3
    "user_id" => 9725
    "elo_matches" => 7
    "elo_rating" => 994.520367143
  ]
  "3-1593" => array:4 [
    "league_id" => 3
    "user_id" => 1593
    "elo_matches" => 4
    "elo_rating" => 987.448354356
  ]
  "3-78" => array:4 [
    "league_id" => 3
    "user_id" => 78
    "elo_matches" => 16
    "elo_rating" => 984.927509938
  ]
  "3-20837" => array:4 [
    "league_id" => 3
    "user_id" => 20837
    "elo_matches" => 4
    "elo_rating" => 981.533602402
  ]
  "3-25" => array:4 [
    "league_id" => 3
    "user_id" => 25
    "elo_matches" => 3
    "elo_rating" => 977.651701927
  ]
  "3-2056" => array:4 [
    "league_id" => 3
    "user_id" => 2056
    "elo_matches" => 8
    "elo_rating" => 978.374247502
  ]
  "3-14300" => array:4 [
    "league_id" => 3
    "user_id" => 14300
    "elo_matches" => 9
    "elo_rating" => 958.218292232
  ]
  "3-16900" => array:4 [
    "league_id" => 3
    "user_id" => 16900
    "elo_matches" => 3
    "elo_rating" => 957.66758785
  ]
  "3-5" => array:4 [
    "league_id" => 3
    "user_id" => 5
    "elo_matches" => 3
    "elo_rating" => 955.441682773
  ]
  "3-11793" => array:4 [
    "league_id" => 3
    "user_id" => 11793
    "elo_matches" => 3
    "elo_rating" => 956.118019821
  ]
  "3-23" => array:4 [
    "league_id" => 3
    "user_id" => 23
    "elo_matches" => 1
    "elo_rating" => 950.0
  ]
  "3-160" => array:4 [
    "league_id" => 3
    "user_id" => 160
    "elo_matches" => 6
    "elo_rating" => 946.346810828
  ]
  "3-11882" => array:4 [
    "league_id" => 3
    "user_id" => 11882
    "elo_matches" => 3
    "elo_rating" => 943.113557791
  ]
  "3-178" => array:4 [
    "league_id" => 3
    "user_id" => 178
    "elo_matches" => 3
    "elo_rating" => 940.38037017
  ]
  "3-2113" => array:4 [
    "league_id" => 3
    "user_id" => 2113
    "elo_matches" => 3
    "elo_rating" => 940.343382565
  ]
  "3-1334" => array:4 [
    "league_id" => 3
    "user_id" => 1334
    "elo_matches" => 2
    "elo_rating" => 923.336202927
  ]
  "3-184" => array:4 [
    "league_id" => 3
    "user_id" => 184
    "elo_matches" => 2
    "elo_rating" => 920.326252901
  ]
  "3-2162" => array:4 [
    "league_id" => 3
    "user_id" => 2162
    "elo_matches" => 2
    "elo_rating" => 917.932985501
  ]
  "3-2058" => array:4 [
    "league_id" => 3
    "user_id" => 2058
    "elo_matches" => 6
    "elo_rating" => 905.641833006
  ]
  "3-1951" => array:4 [
    "league_id" => 3
    "user_id" => 1951
    "elo_matches" => 2
    "elo_rating" => 906.136056131
  ]
  "3-1749" => array:4 [
    "league_id" => 3
    "user_id" => 1749
    "elo_matches" => 2
    "elo_rating" => 905.570092295
  ]
  "3-15296" => array:4 [
    "league_id" => 3
    "user_id" => 15296
    "elo_matches" => 2
    "elo_rating" => 901.02829192
  ]
  "3-11684" => array:4 [
    "league_id" => 3
    "user_id" => 11684
    "elo_matches" => 2
    "elo_rating" => 901.02829192
  ]
  "3-940" => array:4 [
    "league_id" => 3
    "user_id" => 940
    "elo_matches" => 2
    "elo_rating" => 899.735074733
  ]
  "3-12235" => array:4 [
    "league_id" => 3
    "user_id" => 12235
    "elo_matches" => 2
    "elo_rating" => 900.0
  ]
  "3-2957" => array:4 [
    "league_id" => 3
    "user_id" => 2957
    "elo_matches" => 2
    "elo_rating" => 900.0
  ]
  "3-14959" => array:4 [
    "league_id" => 3
    "user_id" => 14959
    "elo_matches" => 2
    "elo_rating" => 894.798068073
  ]
  "3-779" => array:4 [
    "league_id" => 3
    "user_id" => 779
    "elo_matches" => 5
    "elo_rating" => 874.675970857
  ]
  "3-110" => array:4 [
    "league_id" => 3
    "user_id" => 110
    "elo_matches" => 4
    "elo_rating" => 849.309123925
  ]
  "3-5837" => array:4 [
    "league_id" => 3
    "user_id" => 5837
    "elo_matches" => 4
    "elo_rating" => 821.601462523
  ]
]

如果你仔细观察这个结果数组,你会注意到它没有完全正确排序。例如,它将1039.26666217置于1038.639591461038.88789903之下。

有关如何解决此问题的任何想法?

2 个答案:

答案 0 :(得分:3)

您将从函数返回十进制值,documentation警告。

  

比较函数必须返回小于,等于或的整数   如果第一个参数被认为是大于零   分别小于,等于或大于第二个。注意   在PHP 7.0.0之前,这个整数必须在以下范围内   -2147483648至2147483647。

     

警告从比较函数返回非整数值,   比如float,会导致内部强制转换为整数   回调的回报值。因此,诸如0.99和0.1之类的值都将是   强制转换为0的整数值,这将比较这些值   相等。

更改您的函数以返回一个整数来解决问题。

uasort($newRanks, create_function(
    '$b, $a', 'return ($a["elo_rating"] > $b["elo_rating"])?-1:1;'
));

答案 1 :(得分:1)

两个问题:

  1. 您正在使用内部使用create_function()的{​​{1}},这是一个巨大的安全漏洞,无需启动。只需使用实际的匿名函数。
  2. 你的函数参数是倒退的。
  3. Willem Renzema提出了关于返回值的隐式演员的有效观点,但我不喜欢这个解决方案。
  4. 所以:

    eval()

    其中$epsilon = 0.000000001; uasort( $newRanks, function($a,$b)use($epsilon}{ $diff = $a["elo_rating"] - $b["elo_rating"]; if( abs($diff) < $epsilon ) { return 0; } else if( $diff > 0 ) { return 1; } else { return -1; } ) ); 是专门为此比较选择的值,您认为任何$epsilon小于等值,即浮点/舍入误差。

    请参阅:What is the most effective way for float and double comparison?