使用usort()对具有层次排序标准的二维数组进行排序

时间:2023-01-21 21:31:24

Trying to sort an 2-dimensional array of pizza toppings by the category of topping it belongs to. But the way the client supplies the data isn't ideal for this. Here's a sample of the data:

试着按披萨配料所属的类别对二维的披萨配料进行排序。但是客户机提供数据的方式并不理想。以下是数据的样本:

        [0] => Array
            (
                [id] => 30
                [title] => Pepperoni
                [meat] => 1
                [veggie] => 
                [sauce] => 
                [cheese] => 
                [condiment] => 
            )

        [1] => Array
            (
                [id] => 29
                [title] => Onions
                [meat] => 
                [veggie] => 1
                [sauce] => 
                [cheese] => 
                [condiment] => 
            )

The idea is that the toppings should always be grouped by a type (ie. meat) in a specific order (ie. meats followed by veggies followed by sauces and so on)—independent of the order in which they're retrieved. Importantly, no topping ever belongs to two types.

其思想是,浇头应该总是按类型(ie)来分组。肉)按特定的顺序。肉类接着是蔬菜,然后是酱汁,等等)- - -独立于它们被回收的顺序。重要的是,任何浇头都不属于两种类型。

Here's my stab at this:

以下是我对此的尝试:

$topping_options = array()  // ie. the sample data above
usort($topping_options,
                function($opt_a, $opt_b) {
                    $scores = array("a" =>  0, "b" => 0);
                    foreach( array("a" => $opt_a, "b" => $opt_b) as $index => $opt) {
                        if ($opt['meat']) $scores[$index] = 5;
                        if ($opt['veggie']) $scores[$index] = 4;
                        if ($opt['sauce']) $scores[$index] = 3;
                        if ($opt['cheese']) $scores[$index] = 2;
                        if ($opt['condiment']) $scores[$index] = 1;
                    }

                    return $scores['a'] - $scores['b'];
                }
            );

This doesn't at all achieve my aims and I don't understand why; it seems to me that whenever $opt_a has a higher score than $opt_b it should keep it's position while $opt_b gets sent down a rung for further comparisons. Would like to understand what I'm doing wrong. Thanks.

这根本不能实现我的目标,我也不明白为什么;在我看来,每当$opt_a的分数高于$opt_b时,它就应该保持它的位置,而$opt_b则会被降级以进行进一步的比较。我想知道我做错了什么。谢谢。

2 个解决方案

#1


2  

  1. I think that your code is correct and problem in test data. Reorder them to see result
  2. 我认为您的代码是正确的,并且测试数据存在问题。重新排序以查看结果
  3. To obtain correct result order, change code to

    要获得正确的结果顺序,请将代码更改为

    return $scores['b'] - $scores['a'];

    返回分数[b]-几十美元[a];

#2


2  

Here's one way to approach the situation. I've just separated all of the toppings into their own array and then merged them together at the end:

这里有一种处理这种情况的方法。我把所有的浇头都分解成它们自己的数组,最后把它们合并到一起:

<?php
$toppings = array(
    array('id'=>1,'title'=>'M1','meat'=>1,'veggie'=>NULL,'sauce'=>NULL,'cheese'=>NULL,'condiment'=>NULL),
    array('id'=>2,'title'=>'V1','meat'=>NULL,'veggie'=>1,'sauce'=>NULL,'cheese'=>NULL,'condiment'=>NULL),
    array('id'=>3,'title'=>'M2','meat'=>1,'veggie'=>NULL,'sauce'=>NULL,'cheese'=>NULL,'condiment'=>NULL),
    array('id'=>4,'title'=>'V2','meat'=>NULL,'veggie'=>1,'sauce'=>NULL,'cheese'=>NULL,'condiment'=>NULL),
    array('id'=>5,'title'=>'M3','meat'=>1,'veggie'=>NULL,'sauce'=>NULL,'cheese'=>NULL,'condiment'=>NULL)
);

$categories = array(
    'meat',
    'veggie',
    'sauce',
    'cheese',
    'condiment'
);

$segregated_toppings = array();

foreach($toppings as $topping){

    foreach($categories as $c){
        if($topping[$c]){
            if(!isset($segregated_toppings[$c])){
                $segregated_toppings[$c] = array();
            }

            $segregated_toppings[$c][] = $topping;
        }
    }
}

#echo '<pre>',print_r($segregated_toppings),'</pre>';

$sorted_array = call_user_func_array('array_merge',$segregated_toppings);

echo '<pre>',print_r($sorted_array),'</pre>';

#1


2  

  1. I think that your code is correct and problem in test data. Reorder them to see result
  2. 我认为您的代码是正确的,并且测试数据存在问题。重新排序以查看结果
  3. To obtain correct result order, change code to

    要获得正确的结果顺序,请将代码更改为

    return $scores['b'] - $scores['a'];

    返回分数[b]-几十美元[a];

#2


2  

Here's one way to approach the situation. I've just separated all of the toppings into their own array and then merged them together at the end:

这里有一种处理这种情况的方法。我把所有的浇头都分解成它们自己的数组,最后把它们合并到一起:

<?php
$toppings = array(
    array('id'=>1,'title'=>'M1','meat'=>1,'veggie'=>NULL,'sauce'=>NULL,'cheese'=>NULL,'condiment'=>NULL),
    array('id'=>2,'title'=>'V1','meat'=>NULL,'veggie'=>1,'sauce'=>NULL,'cheese'=>NULL,'condiment'=>NULL),
    array('id'=>3,'title'=>'M2','meat'=>1,'veggie'=>NULL,'sauce'=>NULL,'cheese'=>NULL,'condiment'=>NULL),
    array('id'=>4,'title'=>'V2','meat'=>NULL,'veggie'=>1,'sauce'=>NULL,'cheese'=>NULL,'condiment'=>NULL),
    array('id'=>5,'title'=>'M3','meat'=>1,'veggie'=>NULL,'sauce'=>NULL,'cheese'=>NULL,'condiment'=>NULL)
);

$categories = array(
    'meat',
    'veggie',
    'sauce',
    'cheese',
    'condiment'
);

$segregated_toppings = array();

foreach($toppings as $topping){

    foreach($categories as $c){
        if($topping[$c]){
            if(!isset($segregated_toppings[$c])){
                $segregated_toppings[$c] = array();
            }

            $segregated_toppings[$c][] = $topping;
        }
    }
}

#echo '<pre>',print_r($segregated_toppings),'</pre>';

$sorted_array = call_user_func_array('array_merge',$segregated_toppings);

echo '<pre>',print_r($sorted_array),'</pre>';