【问题标题】:Multi-dimensional sorting with variable amount of sorting criteria具有可变排序标准的多维排序
【发布时间】:2021-05-28 18:45:26
【问题描述】:

我正在寻找一种基于可变数量的排序键对多维数组进行排序的方法。

举个例子:

        Array
(
    [0] => Array
        (
            [userId] => 2
            [amounts] => Array
                (
                    [pencils] => 6
                    [phones] => 2
                    [watches] => 3
                    [balls] => 2
                )

        )

    [1] => Array
        (
            [userId] => 1
            [amounts] => Array
                (
                    [pencils] => 6
                    [phones] => 3
                    [watches] => 4
                    [balls] => 1
                )

        )

    [2] => Array
        (
            [userId] => 3
            [amounts] => Array
                (
                    [pencils] => 3
                    [phones] => 3
                    [watches] => 4
                    [balls] => 2
                )

        )

)

例如,我想先按电话对该数组进行排序,如果该值相同,则按手表,然后按球,然后按铅笔。

所以基本上,结果应该是:

        Array
(
    [0] => Array
        (
            [userId] => 3
            [amounts] => Array
                (
                    [pencils] => 3
                    [phones] => 3
                    [watches] => 4
                    [balls] => 2
                )

        )

    [1] => Array
        (
            [userId] => 1
            [amounts] => Array
                (
                    [pencils] => 6
                    [phones] => 3
                    [watches] => 4
                    [balls] => 1
                )

        )

    [2] => Array
        (
            [userId] => 2
            [amounts] => Array
                (
                    [pencils] => 6
                    [phones] => 2
                    [watches] => 3
                    [balls] => 2
                )

        )

)

现在,棘手的部分是在原始数组中,数量数组中的东西(例如铅笔、电话、手表、球)可以是可变的。因此,可能有 4 个类似示例,但也可能只有一个项目,或 5 个或...

我被分类弄湿了,尝试诸如

之类的东西
usort($array, function($a, $b) {
    return $a['amounts']['phones'] <=> $b['amounts']['watch'];
});

但我现在卡住了,不知道如何解锁自己。

非常感谢任何帮助!我正在使用 PHP 7。

更新:

根据 cmets 的要求,这是来自第一个数组的 var_export:

array (
  0 => 
  array (
    'userId' => '2',
    'amounts' => 
    array (
      'pencils' => '6',
      'phones' => '2',
      'watches' => '3',
      'balls' => '2',
    ),
  ),
  1 => 
  array (
    'userId' => '1',
    'amounts' => 
    array (
      'pencils' => '6',
      'phones' => '3',
      'watches' => '4',
      'balls' => '1',
    ),
  ),
  2 => 
  array (
    'userId' => '3',
    'amounts' => 
    array (
      'pencils' => '3',
      'phones' => '3',
      'watches' => '4',
      'balls' => '2',
    ),
  ),
)

【问题讨论】:

  • 所以如果它们是可变的。你有没有这个值按优先级排序的数组?
  • @nice_dev 是的,就是这样,只是一个简单的array('phones','watches','balls','pencils'),其中顺序是优先级。
  • 好的,你可以分享你的数组的 var_export() 吗?
  • 我用请求的 var_export 更新了我的帖子。至于你的最后一个问题:那是不可能的。所有子数组将始终包含定义顺序的数组中定义的所有项(可能值为 0)。
  • 所以它们是可变的,因为可以有 4 个(如示例中)或 3 或 7 个或任何值,但如果是例如 7 个,则所有子数组都将具有这 7 个项。

标签: php multidimensional-array


【解决方案1】:

好的,所以usort() 是正确的路径。为了解决这个问题,您可以将优先级数组传递给回调,遍历优先级数组并一一检查每个参数。如果从头到尾的过程中有任何一个碰巧不相等,则返回它们的比较差异。您可以在最后返回0,这意味着将元素保持在排序顺序中,因为它们是相等的。

$priority = array('phones','watches','balls','pencils');

usort($array,function($a,$b) use ($priority){
    foreach($priority as $p){
        if($a['amounts'][$p] != $b['amounts'][$p]) return $b['amounts'][$p] <=> $a['amounts'][$p];
    }
        
    return 0;
});


print_r($array);

【讨论】:

  • 太棒了,非常感谢您的解释!只需在末尾添加 array_reverse 即可。
  • @binoculars 很高兴为您提供帮助,但您能告诉我为什么最后需要 array_reverse() 吗?
  • 好吧,尝试您的解决方案,我注意到最终数组的顺序相反。所以手机数量最多的实际上是在数组的末尾,而我希望它在顶部(参见第一篇文章中的示例响应)
  • @binoculars 好的,所以你可以像$b['amounts'][$p] &lt;=&gt; $a['amounts'][$p]; 一样更改条件(我也更新了我的答案)
  • 说得有道理,我自己也应该考虑过。谢谢!
【解决方案2】:

这只是为了好玩,一定有更好的方法,但您不必只对 $order 数组的键进行硬编码:

$order = ['phones','watches','balls','pencils'];

array_multisort(array_map(function($v) use($order) {
                              return implode('-', array_merge(array_flip($order), $v['amounts']));
                          }, $array), $array);
  • 将每个amounts 数组合并到$order 数组中(翻转以获取键)会将amounts$order 排序,然后将implode 排序为字符串
  • 现在您有一个匹配的字符串数组,例如 ['6-2-3-2','6-3-4-1'] 进行排序,用于对原始字符串进行排序
  • 按升序排序或使用SORT_DESC

PHP >= 7.4

array_multisort(array_map(fn($v) => implode('-', array_merge(array_flip($order), $v['amounts'])),
                $array), $array);

更简单的说明:

foreach($array as $v) {
    $strings[] = implode('-', array_merge(array_flip($order), $v['amounts']));
}
array_multisort($strings, $array);

【讨论】:

  • 我正在尝试遵循您的解决方案。如果我理解正确,如果任何 2 个不同参数的金额类似于 612612,它不会引起问题吗?
  • 好吧!是的,我一直掉进那个陷阱:-(
  • 没有问题。不幸的是,我自己也经历了这一切。
  • 可能在- 上内爆?对于61-26-12
  • 也许吧。我自己没有使用过array_multisort()。
猜你喜欢
  • 2014-07-08
  • 2019-09-29
  • 1970-01-01
  • 2018-04-13
  • 1970-01-01
  • 2016-06-11
  • 2015-10-20
  • 2020-03-20
  • 1970-01-01
相关资源
最近更新 更多