为什么使用比较函数按布尔值对关联数组进行排序会反转数组顺序?
Why does sorting an associative array by a boolean value using a comparison function reverse the array order?
我有一个关联数组:
Array(
[110] => Array
(
[releaseDate] => 2020-08-15 00:00:00
[isNewest] =>
)
[128] => Array
(
[releaseDate] => 2020-08-01 00:00:00
[isNewest] =>
)
[129] => Array
(
[releaseDate] => 2020-08-01 00:00:00
[isNewest] =>
)
[130] => Array
(
[releaseDate] => 2020-08-01 00:00:00
[isNewest] =>
)
[132] => Array
(
[releaseDate] => 2020-08-01 00:00:00
[isNewest] =>
)
[123] => Array
(
[releaseDate] => 2020-07-01 00:00:00
[isNewest] =>
)
[124] => Array
(
[releaseDate] => 2020-07-01 00:00:00
[isNewest] =>
)
[125] => Array
(
[releaseDate] => 2020-07-01 00:00:00
[isNewest] =>
)
[127] => Array
(
[releaseDate] => 2020-07-01 00:00:00
[isNewest] =>
)
)
通常这应该按 releaseDate
排序,但 isNewest
为真的元素应该排在第一位。
我使用 uasort()
来完成:
uasort($arr, function($a, $b){
return $a['isNewest'] - $b['isNewest'];
});
有时 isNewest
是正确的,但在这个例子中(以及在数据条件下我首先发现了这个错误)isNewest
对于所有条目都是 false
。
运行以上,这是结果:
Array
(
[124] => Array
(
[releaseDate] => 2020-07-01 00:00:00
[isNewest] =>
)
[125] => Array
(
[releaseDate] => 2020-07-01 00:00:00
[isNewest] =>
)
[127] => Array
(
[releaseDate] => 2020-07-01 00:00:00
[isNewest] =>
)
[123] => Array
(
[releaseDate] => 2020-07-01 00:00:00
[isNewest] =>
)
[132] => Array
(
[releaseDate] => 2020-08-01 00:00:00
[isNewest] =>
)
[128] => Array
(
[releaseDate] => 2020-08-01 00:00:00
[isNewest] =>
)
[129] => Array
(
[releaseDate] => 2020-08-01 00:00:00
[isNewest] =>
)
[130] => Array
(
[releaseDate] => 2020-08-01 00:00:00
[isNewest] =>
)
[110] => Array
(
[releaseDate] => 2020-08-15 00:00:00
[isNewest] =>
)
)
问题是按照我的方式对数组进行排序,使用 uasort()
似乎颠倒了数组顺序。如果你查看上面的两个数组并检查 releaseDate
,你就会明白我的意思了。
如果 isNewest
对任何条目都为真,则它们会排在第一位,但数组顺序的其余部分最终仍会被颠倒。
我似乎无法理解 uasort()
比较功能的工作原理。我尝试返回 -1
和 1
,甚至翻转 $a
和 $b
参数,但无济于事。
我在这里做错了什么?我如何在这里正确使用 uasort()
,以便数组保持按 releaseDate
降序排序,但是这样 isNewest
设置为 true
的条目就会出现第一个?
谢谢!
当每个isNewest
设置为false
时,我无法reproduce反转。
为了得到你想要的第一个(isNewest
)和第二个(releaseDate
)顺序排序的结果,你可以简单地使用 uasort
两次 - 最后使用最高优先级排序。
uasort($input, fn($a, $b) => strtotime($b['releaseDate']) - strtotime($a['releaseDate']));
uasort($input, fn($a, $b) => $b['isNewest'] - $a['isNewest']);
工作example。
您也可以使用 array_multisort 以防您不需要密钥。 (数字键将丢失)。
array_multisort(
array_column($input, 'isNewest'),
SORT_DESC, // 1 before 0 (true before false)
array_column($input, 'releaseDate'),
SORT_DESC,
$input
);
工作example。
未来的小费。此处使用 var_export 到 post 数据。所以我们可以简单地copy/paste它在代码中使用它。
如果你想让 isRelease=true
个候选人在每个 sub-group(releaseDate
)中排在首位 - 翻转 uasort
或 array_columns
在 array_multisort
.
您可以使用单个 uasort
调用对数据进行排序,首先检查日期是否相等(如果不相等,则返回排序结果),然后首先对 true
值进行排序:
uasort($array, function ($a, $b) {
// if dates not equal, return result of comparison
// since dates are in Y-m-d H:i:s format we can compare as strings
if (($rdcmp = strcmp($a['releaseDate'], $b['releaseDate'])) != 0) return $rdcmp;
// dates are equal, so sort true values first
if ($a['isNewest'] && !$b['isNewest']) return -1;
elseif (!$a['isNewest'] && $b['isNewest']) return 1;
else return 0;
});
print_r($array);
或者要对false
之前的所有true
值进行排序,然后按releaseDate
排序,可以使用此代码:
uasort($array, function ($a, $b) {
// sort true values first
if ($a['isNewest'] && !$b['isNewest']) return -1;
elseif (!$a['isNewest'] && $b['isNewest']) return 1;
// boolean values are equal, so sort by date.
// Since dates are in Y-m-d H:i:s format, we can sort as strings
else return strcmp($a['releaseDate'], $b['releaseDate']);
});
请注意,如果您想按 releaseDate
降序排序,您应该更改
strcmp($a['releaseDate'], $b['releaseDate'])
到
strcmp($b['releaseDate'], $a['releaseDate'])
还要注意如果你的布尔值实际上是true
和false
,你可以简化布尔值比较
return $b['isNewest'] - $a['isNewest'];
否则,由于 PHP 将所有类型的值都视为 true
(包括负数,这可能会弄乱减法排序),像我所做的那样进行特定比较更安全在代码块中。
我有一个关联数组:
Array(
[110] => Array
(
[releaseDate] => 2020-08-15 00:00:00
[isNewest] =>
)
[128] => Array
(
[releaseDate] => 2020-08-01 00:00:00
[isNewest] =>
)
[129] => Array
(
[releaseDate] => 2020-08-01 00:00:00
[isNewest] =>
)
[130] => Array
(
[releaseDate] => 2020-08-01 00:00:00
[isNewest] =>
)
[132] => Array
(
[releaseDate] => 2020-08-01 00:00:00
[isNewest] =>
)
[123] => Array
(
[releaseDate] => 2020-07-01 00:00:00
[isNewest] =>
)
[124] => Array
(
[releaseDate] => 2020-07-01 00:00:00
[isNewest] =>
)
[125] => Array
(
[releaseDate] => 2020-07-01 00:00:00
[isNewest] =>
)
[127] => Array
(
[releaseDate] => 2020-07-01 00:00:00
[isNewest] =>
)
)
通常这应该按 releaseDate
排序,但 isNewest
为真的元素应该排在第一位。
我使用 uasort()
来完成:
uasort($arr, function($a, $b){
return $a['isNewest'] - $b['isNewest'];
});
有时 isNewest
是正确的,但在这个例子中(以及在数据条件下我首先发现了这个错误)isNewest
对于所有条目都是 false
。
运行以上,这是结果:
Array
(
[124] => Array
(
[releaseDate] => 2020-07-01 00:00:00
[isNewest] =>
)
[125] => Array
(
[releaseDate] => 2020-07-01 00:00:00
[isNewest] =>
)
[127] => Array
(
[releaseDate] => 2020-07-01 00:00:00
[isNewest] =>
)
[123] => Array
(
[releaseDate] => 2020-07-01 00:00:00
[isNewest] =>
)
[132] => Array
(
[releaseDate] => 2020-08-01 00:00:00
[isNewest] =>
)
[128] => Array
(
[releaseDate] => 2020-08-01 00:00:00
[isNewest] =>
)
[129] => Array
(
[releaseDate] => 2020-08-01 00:00:00
[isNewest] =>
)
[130] => Array
(
[releaseDate] => 2020-08-01 00:00:00
[isNewest] =>
)
[110] => Array
(
[releaseDate] => 2020-08-15 00:00:00
[isNewest] =>
)
)
问题是按照我的方式对数组进行排序,使用 uasort()
似乎颠倒了数组顺序。如果你查看上面的两个数组并检查 releaseDate
,你就会明白我的意思了。
如果 isNewest
对任何条目都为真,则它们会排在第一位,但数组顺序的其余部分最终仍会被颠倒。
我似乎无法理解 uasort()
比较功能的工作原理。我尝试返回 -1
和 1
,甚至翻转 $a
和 $b
参数,但无济于事。
我在这里做错了什么?我如何在这里正确使用 uasort()
,以便数组保持按 releaseDate
降序排序,但是这样 isNewest
设置为 true
的条目就会出现第一个?
谢谢!
当每个isNewest
设置为false
时,我无法reproduce反转。
为了得到你想要的第一个(isNewest
)和第二个(releaseDate
)顺序排序的结果,你可以简单地使用 uasort
两次 - 最后使用最高优先级排序。
uasort($input, fn($a, $b) => strtotime($b['releaseDate']) - strtotime($a['releaseDate']));
uasort($input, fn($a, $b) => $b['isNewest'] - $a['isNewest']);
工作example。
您也可以使用 array_multisort 以防您不需要密钥。 (数字键将丢失)。
array_multisort(
array_column($input, 'isNewest'),
SORT_DESC, // 1 before 0 (true before false)
array_column($input, 'releaseDate'),
SORT_DESC,
$input
);
工作example。
未来的小费。此处使用 var_export 到 post 数据。所以我们可以简单地copy/paste它在代码中使用它。
如果你想让 isRelease=true
个候选人在每个 sub-group(releaseDate
)中排在首位 - 翻转 uasort
或 array_columns
在 array_multisort
.
您可以使用单个 uasort
调用对数据进行排序,首先检查日期是否相等(如果不相等,则返回排序结果),然后首先对 true
值进行排序:
uasort($array, function ($a, $b) {
// if dates not equal, return result of comparison
// since dates are in Y-m-d H:i:s format we can compare as strings
if (($rdcmp = strcmp($a['releaseDate'], $b['releaseDate'])) != 0) return $rdcmp;
// dates are equal, so sort true values first
if ($a['isNewest'] && !$b['isNewest']) return -1;
elseif (!$a['isNewest'] && $b['isNewest']) return 1;
else return 0;
});
print_r($array);
或者要对false
之前的所有true
值进行排序,然后按releaseDate
排序,可以使用此代码:
uasort($array, function ($a, $b) {
// sort true values first
if ($a['isNewest'] && !$b['isNewest']) return -1;
elseif (!$a['isNewest'] && $b['isNewest']) return 1;
// boolean values are equal, so sort by date.
// Since dates are in Y-m-d H:i:s format, we can sort as strings
else return strcmp($a['releaseDate'], $b['releaseDate']);
});
请注意,如果您想按 releaseDate
降序排序,您应该更改
strcmp($a['releaseDate'], $b['releaseDate'])
到
strcmp($b['releaseDate'], $a['releaseDate'])
还要注意如果你的布尔值实际上是true
和false
,你可以简化布尔值比较
return $b['isNewest'] - $a['isNewest'];
否则,由于 PHP 将所有类型的值都视为 true
(包括负数,这可能会弄乱减法排序),像我所做的那样进行特定比较更安全在代码块中。