按值对多维数组排序 - 先奇数,后偶数

问题描述 投票:0回答:2

我正在使用多维数组。每个数组都包含沿街道的属性,其中一个值是街道地址。

我想对数组进行排序,使得对于每条街道,奇数地址都列在偶数地址之前。它已经按数字排序(从最低到最高),所以我唯一想弄清楚的是如何在偶数之前对赔率进行排序。

$array = array(
    array('apn' => 345345345, 'sqft' => 1200, 'address' => '323 Pacific Ave.'),
    array('apn' => 345345342, 'sqft' => 1421, 'address' => '324 Pacific Ave.'),
    array('apn' => 345345346, 'sqft' => 1012, 'address' => '325 Pacific Ave.'),
    array('apn' => 345345347, 'sqft' => 1093, 'address' => '328 Pacific Ave.'),
    array('apn' => 345345353, 'sqft' => 1121, 'address' => '12 Lincoln Ave.'),
    array('apn' => 345345351, 'sqft' => 1643, 'address' => '13 Lincoln Ave.'),
    array('apn' => 345345352, 'sqft' => 1222, 'address' => '14 Lincoln Ave.')
);

目前我有以下内容:

usort($array, function($a, $b)
{
    if ($a['address'] % 2 == $b['address'] % 2) {
        if ($a['address'] == $b['address']) {
            return 0;
        }
        return ($a['address'] < $b['address']) ? -1 : 1;
    }    
    return ($a['address'] % 2 == 0) ? 1 : -1;
});

问题在于,它会导致所有偶数之前列出的所有赔率,而不是该街道前夕之前每条街道的所有赔率,如下所示:

Array
(
    [0] => Array
        (
            [apn] => 345345341
            [sqft] => 1001
            [address] => 13 Lincoln Ave.
        )
    [1] => Array
        (
            [apn] => 345345341
            [sqft] => 1001
            [address] => 12 Lincoln Ave.
        )

    [2] => Array
        (
            [apn] => 345345341
            [sqft] => 1001
            [address] => 14 Lincoln Ave.
        )

    [3] => Array
        (
            [apn] => 345345345
            [sqft] => 1200
            [address] => 323 Pacific Ave.
        )

    [4] => Array
        (
            [apn] => 345345341
            [sqft] => 1001
            [address] => 325 Pacific Ave.
        )

    [5] => Array
        (
            [apn] => 345345342
            [sqft] => 1421
            [address] => 324 Pacific Ave.
        )

    [6] => Array
        (
            [apn] => 345345341
            [sqft] => 1001
            [address] => 328 Pacific Ave.
        )

)
php
2个回答
1
投票

所以那就是:

usort($array, function($x, $y)
{
   $x = preg_split('/^(\d+)\s+(.*)/', $x['address'], -1 , 3);
   $y = preg_split('/^(\d+)\s+(.*)/', $y['address'], -1 , 3);
   $x[2] = $x[0] % 2;
   $y[2] = $y[0] % 2;
   if($x[1]==$y[1]) //first level: streets
   {
      if($x[2]==$y[2]) //second level: oddity
         return $x[0]<$y[0]?-1:$x[0]!=$y[0]; //third level: numeric order
      return $x[2]>$y[2]?-1:1;
   }
   return $x[1]<$y[1]?-1:1;
});

注意,你的困难是因为你实际上有 3 个排序级别:

  • 第一层:街道。您希望街道成为结果数组中排序的顶层
  • 第二层:奇怪。你希望奇数在偶数之前
  • 第三级:自然数字顺序 - 在相同的奇怪之处内,您希望数字将按自然顺序排序

Fiddle 可以在这里使用。另外,

preg_split()
可能不是分开号码和街道的最佳解决方案,但我不确定常见情况。对此进行一些解释,
-1
表示“结果中的元素没有限制”,
3
表示
PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY
(查看我提供的链接以获取更多详细信息)。


0
投票

usort()
内解析地址和执行计算将不会具有高性能。 将排序标准准备为单独的数组,然后使用
array_multisort()
进行排序。 演示

$isEvens = [];
$numbers = [];
$streets = [];
foreach ($array as ['address' => $a]) {
    if (sscanf($a, "%s %[^\n]", $n, $s) === 2) {
        $isEvens[] = !((int)$n & 1);
        $numbers[] = $n;
        $streets[] = $s;
    } else {
        $isEvens[] = !((int)$a & 1);
        $numbers[] = $a;
        $streets[] = $a;
    }
}

array_multisort(
    $streets,
    $isEvens,
    $numbers,
    $array
);
var_export($array);
© www.soinside.com 2019 - 2024. All rights reserved.