将数组中特定值的元素移动到数组顶部

5

我有一个类似于这样的数组:

Array
(
  [0] => stdClass Object
    (
      [Leasing] => 12939.74
      [Name] => Jeremy
      [Rental] => 0
      [Sales] => 56603.13
      [Total] => 69542.87
    )
  [1] => stdClass Object
    (
      [Leasing] => 0
      [Name] => Shaun
      [Rental] => 0
      [Sales] => 58590
      [Total] => 58590
    )
  [2] => stdClass Object
    (
      [Leasing] => 0
      [Name] => Lindsay
      [Rental] => 0
      [Sales] => 22951.97
      [Total] => 22951.97
    )
  [3] => stdClass Object
    (
      [Leasing] => 0
      [Name] => Sally
      [Rental] => 1200
      [Sales] => 21624.9
      [Total] => 22824.9
    )
  [4] => stdClass Object
    (
      [Leasing] => 0
      [Name] => House
      [Rental] => 0
      [Sales] => 16235.81
      [Total] => 16235.81
    )
  [5] => stdClass Object
    (
      [Leasing] => 5298.85
      [Name] => Bill
      [Rental] => 1200
      [Sales] => 0
      [Total] => 6498.85
    )
)

目前,使用以下方式按总数对数组进行排序:

usort($data, function ($a, $b) {
    return $b->Total - $a->Total;
});

我需要始终使名为House的人位于数组的顶部。 我的想法是保持按Total排序(因为我仍然需要这样),然后将带有House值的元素放在数组的开头。 我可以将特定的KEY放在顶部,但是KEY可能会根据谁拥有最高总数而改变。 如何始终将名为House的人放在数组的顶部?


一种方法:将所需的第一个元素放在第一个位置,将数组分成该元素和其他所有元素,然后对其他部分进行排序。抱歉,我不记得PHP语法足够好以提供正确的答案。 - GreenMatt
你的排序函数返回值将被 usort 强制转换为整数,因此它会将 0.05 和 0.95 视为相等。 - Sammitch
2个回答

16

这应该可以工作:

usort($data, function ($a, $b) {
    if ($a->Name != "House" && $b->Name == "House") {
        return 1;
    } elseif ($a->Name == "House" && $b->Name != "House") {
        return -1;
    } else {
        return $b->Total - $a->Total;
    }
});

来自PHP: usort - Manual

比较函数必须返回一个整数,如果第一个参数被认为比第二个参数小,则返回一个小于零的整数;如果第一个参数被认为等于第二个参数,则返回零;如果第一个参数被认为比第二个参数大,则返回一个大于零的整数。

在这种情况下,返回1告诉排序函数House大于任何其他值,而-1则表示House小于任何其他值。


运行得非常出色!如果我可以问一下,-1和1有什么意义? - mdance
太棒了,想知道如何使比较函数参数化,例如,如何注入变量而不是硬编码“house”? - Swanand Keskar

2

您的要求:

  1. 按照“名称”列排序——将“房子”价值行放在非“房子”价值行之前。
  2. 按照“总计”列进行降序排序。

从 PHP7 开始,太空船操作符(<=>)通过评估规则数组来使脚本排序规则清晰明了(自左至右读取元素)。

为了首先排序“房子”行,请将每个对象的“名称”字符串评估为与“房子”相同。将“false”评估视为“0”,将“true”评估视为“1”。通过将数据“$b”写在操作符的左侧,实现了降序排序。 “房子”对象将是唯一一个评估为“true”的对象,并且因为它是第一个排序条件,所以它将优先作为对象数组中的第一个对象。

对于不包含“房子”的其他对象,将评估第二个排序条件。通过将“$b”的“总计”值写在左侧,将“$a”的“总计”值写在右侧,再次使用降序排序——这将使具有更高总计的对象排在具有较低总计的对象之前。

代码:(演示

usort(
    $objects,
    fn($a, $b) =>
         [$b->Name === 'House', $b->Total]
         <=>
         [$a->Name === 'House', $a->Total]
);

为了完整性,您也可以使用array_multisort(),但在这种情况下,它将比usort()效率低,因为需要多次函数调用来准备排序列。(演示

array_multisort(
    array_map(fn($obj) => $obj->Name !== 'House', $objects), // ASC puts falses before trues
    array_column($objects, 'Total'),
    SORT_DESC,
    $objects
);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接