2

我正在从数据库接收一个数组 - 我无法控制发送哪些数据以及以什么顺序发送。这是它目前的样子:

Array
(
    [itemCode] => Array
        (
            [0] => Array
                (
                    [code] => P
                    [descShort] => Pepperoni
                )

            [1] => Array
                (
                    [code] => G
                    [descShort] => Green Peppers
                )

            [2] => Array
                (
                    [code] => n
                    [descShort] => No Sauce
                )

            [3] => Array
                (
                    [code] => x
                    [descShort] => No Cheese
                )

            [4] => Array
                (
                    [code] => 
                    [descShort] => Regular Cheese
                )

            [5] => Array
                (
                    [code] => 
                    [descShort] => Regular Sauce
                )

        )

)

在实际实践中,在 No Sauce 选项之前可以有任意数量的元素(目前在索引 3,但并不总是这样。)客户想要的是 Cheese 和 Sauce 项目始终位于列表的末尾,并且以这种方式订购:普通奶酪,无奶酪,普通酱汁,无酱汁。

同样,请记住,我无法控制最初创建数组的方式,并且在相关元素之前和之间可能存在任意数量的其他元素,我该如何实现呢?其他需要担心的是,在某些时候,他们可能希望在此重新排序中包含其他选项(例如,他们可能会添加额外奶酪和额外酱汁的选项,并希望它们处于特定位置好。)

添加了 var_export

array (
  'itemCode' => 
  array (
    0 => 
    array (
      'code' => 'P',
      'descShort' => 'Pepperoni',
    ),
    1 => 
    array (
      'code' => 'G',
      'descShort' => 'Green Peppers',
    ),

    2 => 
    array (
      'code' => 'n',
      'descShort' => 'No Sauce',
    ),
    3 => 
    array (
      'code' => 'x',
      'descShort' => 'No Cheese',
    ),
    4 => 
    array (
      'code' => '',
      'descShort' => 'Regular Cheese',
    ),
    5 => 
    array (
      'code' => '',
      'descShort' => 'Regular Sauce',
    ),
  ),
)
4

3 回答 3

3

您可以尝试使用usort,这将允许用户定义的排序。

于 2012-11-07T16:57:50.600 回答
2

正如已经评论过的那样,该usort功能可以用于此目的。但这只是开始,因为它需要比较功能。

这也不是那么难,因为我们可以创建一个。但是,了解它的工作原理至关重要:

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

好的,这不是一个障碍,而是转变了实际问题,如何找出哪个高于哪个?以及如何做到这一点?

有两种类型的值:不需要任何排序的值或需要排序的值。让我们首先为需要排序的人定义一个数组。为了明确排序是什么,请命名键:

$order    = 'descShort';
$ordering = ['Regular Cheese', 'No Cheese', 'Regular Sauce', 'No Sauce'];

现在在比较函数中,您可以查找 A/B 值是否存在于排序中的条目。如果它不存在,则不需要排序。如果存在,则需要订购。

这两种情况得到了扩展,因为您还可以将现有的排序顺序与不存在的排序顺序结合起来。因此,有四种情况需要涵盖:

  1. A 和 B 不存在 - 平等对待 - 0
  2. A 和 B 存在 - 根据它们的 order-value 排序 - 计算位置 A - B
  3. A 存在但 B 不存在 - A 大于 B -- 1
  4. B 存在但不存在 A - A 小于 B -- -1

由于 PHP 中的函数支持,我们可以轻松地将 order-key 和排序值传递给比较函数,以作为一个快速示例。然后,该功能只需执行针对四种情况概述的操作。

这个例子:

$order    = 'descShort';
$ordering = ['Regular Cheese', 'No Cheese', 'Regular Sauce', 'No Sauce'];
$compare  = function($a, $b) use ($order, $ordering) {
    $hasA = array_search($a[$order], $ordering);
    $hasB = array_search($b[$order], $ordering);

    // nothing to sort
    if ($hasA === $hasB && $hasA === FALSE) {
        return 0;
    }

    // if both are found, sort
    if ($hasA !== FALSE && $hasB !== FALSE) {
        return $hasA - $hasB;
    }

    // as one of them is in there, put it to end
    return $hasA === FALSE ? -1 : 1;
};

usort($array['itemCode'], $compare);

所以现在有一个警告:usort不稳定。这意味着,当返回 0 时,项目不会停留在它们的位置。您可以通过再次排序来解决这个问题usort

usort($array['itemCode'], $compare);

那么最终的排序顺序是(Demo):

Array
(
    [itemCode] => Array
        (
            [0] => Array
                (
                    [code] => P
                    [descShort] => Pepperoni
                )

            [1] => Array
                (
                    [code] => G
                    [descShort] => Green Peppers
                )

            [2] => Array
                (
                    [code] => 
                    [descShort] => Regular Cheese
                )

            [3] => Array
                (
                    [code] => x
                    [descShort] => No Cheese
                )

            [4] => Array
                (
                    [code] => 
                    [descShort] => Regular Sauce
                )

            [5] => Array
                (
                    [code] => n
                    [descShort] => No Sauce
                )
        )
)

由于稳定排序存在问题,而且我对它也不是很好(在您的情况下,建议的函数对我来说有点像开销),所以只有很好的 old foreach.

由于没有重复的值供以后排序的那些,好吧,这留下了一些漂亮的空间:

$order    = 'descShort';
$ordering = ['Regular Cheese', 'No Cheese', 'Regular Sauce', 'No Sauce'];

$result = []; // the final result
$later  = []; // to be sorted later
foreach($array as $element)
{

    $has = array_search($element[$order], $ordering);
    if ($has !== FALSE) {
        $later[$has] = $element;
        continue;
    }

    $result[] = $element;
}

它只是在数组上直接 for-eaching,将所有属于排序的值放入$result已经存在的值中。

那些属于排序的部分$later已经以其订单值作为索引放入。

只有$later这样才用 排序ksort,然后将两部分合并:

ksort($later);
$result = array_merge($result, $later);

并做了。不需要回调函数。只需首先过滤,然后将排序值与索引一起使用ksort即可。演示

于 2012-11-07T17:43:27.543 回答
0

我认为这是您想要的用户定义的排序。该数组$last_options列出了所有应排序到末尾的浇头,它们在数组中的顺序指定了它们应出现在结果中的顺序。

$last_options = array('Regular Cheese', 'No Cheese', 'Regular Sauce', 'No Sauce');

function topping_order($a, $b) {
  $a_pos = array_search($a['descShort'], $last_options);
  $b_pos = array_search($b['descShort'], $last_options);
  if ($a_pos !== false && $b_pos !== false) {
    if ($a_pos > $b_pos) {
      return 1;
    }
    if ($b_pos > $a_pos) {
      return -1;
    }
    return 0;
  }
  if ($a_pos === false) {
    return -1;
  }
  if ($b_pos === false) {
    return 1;
  }
  return 0;
}

usort($array, 'topping_order');
于 2012-11-07T17:43:31.257 回答