简体   繁体   English

按列值 DESC 对多维数组进行排序,然后按另一列 DESC 的长度排序

[英]Sort multidimensional array on column values DESC, then by length of another column DESC

I need to sort some data that is not coming from a database, but is structured like a sql result set.我需要对一些不是来自数据库但结构类似于 sql 结果集的数据进行排序。

In MySQL, I would write a query as follows to sort the data by two columns:在 MySQL 中,我将编写如下查询以按两列对数据进行排序:

SELECT product, qty FROM stock ORDER BY qty DESC, LENGTH(product) DESC 

However, in this case, I need to perform this sorting logic with php.但是,在这种情况下,我需要使用 php 执行此排序逻辑。 Specifically, the rows are sorted first by descending qty , and then by the length of name descending.具体来说,行首先按qty降序排序,然后按name的长度降序排序。

Unsorted Input:未排序的输入:

[
    ['name' => 'foo bar', 'qty' => 6],
    ['name' => 'foo bar bar foo', 'qty' => 10],
    ['name' => 'b', 'qty' => 5],
    ['name' => 'foo', 'qty' => 10],
    ['name' => 'bar', 'qty' => 6],
    ['name' => 'foo bar bar bar foo', 'qty' => 6],
]

After sorting, I need to restructure the data with the name values as keys and the qty values as values of a flat, associative array The finished array would look something like this:排序后,我需要使用name值作为键, qty值作为平面关联数组的值重构数据 完成的数组将如下所示:

Desired Output:期望输出:

[
    'foo bar bar foo' => 10,
    'foo' => 10,
    'foo bar bar bar foo' => 6,
    'foo bar' => 6,
    'bar' => 6,
    'b' => 5
]

take a look at php's usort and uasort .看看 php 的usortuasort

You should be able to define a function that can sort it like that您应该能够定义一个可以像这样对其进行排序的函数

Not sure if it would work easily with that current array but this one it would不确定它是否可以轻松地与当前阵列一起使用,但它会

$array = array(
 array('name' => 'foo bar bar foo', 'qty' => 10 ),
 array('name' => 'foo', 'qty' => 6),
 array('name' => 'foo bar bar foo', 'qty' => 6 ),
 array('name' => 'foo bar', 'qty' => 6 )
);

uasort($array, 'arraySort');

function arraySort($a, $b)
{
    if($a['qty'] > $b['qty'])
        return 1;
    elseif($a['qty'] < $b['qty'])
        return -1;
    else
        if(strlen($a['name']) >= strlen($b['name']))
            return 1;
        else
            return -1;
}

Looking at the answers to this question: PHP array multiple sort - by value then by key?查看这个问题的答案: PHP array multiple sort - by value then by key? , it seems array_multisort is the way to go. ,看来array_multisort是要走的路。 (I'm not really sure how array_multisort works, I just kinda hacked this up, and it seems to work). (我不太确定array_multisort是如何工作的,我只是稍微修改了一下,它似乎有效)。

Try this:试试这个:

$arr = array(
  'foo bar' => 6,
  'foo' => 10,
  'bar' => 6,
  'b' => 5,
  'foo bar bar bar foo' => 6,
  'foo bar bar foo' => 10
);

array_multisort(array_values($arr), SORT_DESC,
  array_map(create_function('$v', 'return strlen($v);'), array_keys($arr)),
  SORT_DESC, $arr);

Demo: http://codepad.org/mAttNIV7演示: http : //codepad.org/mAttNIV7

UPDATE: Added array_map to make it sort by the length of the string, before it was just doing:更新:添加了array_map以使其按字符串的长度排序,然后才执行:

$str1 > $str2 instead of strlen($str1) > strlen($str2) . $str1 > $str2而不是strlen($str1) > strlen($str2)

UPDATE 2: In PHP >= 5.3, you can replace create_function with a real anonymous function.更新 2:在 PHP >= 5.3 中,您可以用真正的匿名函数替换create_function

array_map(function($v){return strlen($v);}, array_keys($arr))

Demo 2: http://codepad.viper-7.com/6qrFwj演示 2: http : //codepad.viper-7.com/6qrFwj

One limitation while sorting the keys on the basis of length is that: equal length keys are not re-ordered.根据长度对键进行排序时的一个限制是:不重新排序等长键。 Say we need to order the keys by length in descending order.假设我们需要按长度descending对键进行排序。

$arr = array(
    "foo 0" => "apple",
    "foo 1" => "ball",
    "foo 2 foo 0 foo 0" => "cat",
    "foo 2 foo 0 foo 1 foo 0" => "dog",
    "foo 2 foo 0 foo 1 foo 1" => "elephant",
    "foo 2 foo 1 foo 0" => "fish",
    "foo 2 foo 1 foo 1" => "giraffe"
);

debug($arr, "before sort");
$arrBad = $arr;
sortKeysDescBAD($arrBad);
debug($arrBad, "after BAD sort");
sortKeysDescGOOD($arr);
debug($arr, "after GOOD sort 2");

function sortKeysDescBAD(&$arrNew) {
    $arrKeysLength = array_map('strlen', array_keys($arrNew));
    array_multisort($arrKeysLength, SORT_DESC, $arrNew);
    //return max($arrKeysLength);
}

function sortKeysDescGOOD(&$arrNew) {
    uksort($arrNew, function($a, $b) {
        $lenA = strlen($a); $lenB = strlen($b);
        if($lenA == $lenB) {
            // If equal length, sort again by descending
            $arrOrig = array($a, $b);
            $arrSort = $arrOrig;
            rsort($arrSort);
            if($arrOrig[0] !== $arrSort[0]) return 1;
        } else {
            // If not equal length, simple
            return $lenB - $lenA;
        }
    });
}

function debug($arr, $title = "") {
    if($title !== "") echo "<br/><strong>{$title}</strong><br/>";
    echo "<pre>"; print_r($arr); echo "</pre><hr/>";
}

Output will be:输出将是:

before sort
Array
(
    [foo 0] => apple
    [foo 1] => ball
    [foo 2 foo 0 foo 0] => cat
    [foo 2 foo 0 foo 1 foo 0] => dog
    [foo 2 foo 0 foo 1 foo 1] => elephant
    [foo 2 foo 1 foo 0] => fish
    [foo 2 foo 1 foo 1] => giraffe
)

after BAD sort
Array
(
    [foo 2 foo 0 foo 1 foo 0] => dog
    [foo 2 foo 0 foo 1 foo 1] => elephant
    [foo 2 foo 0 foo 0] => cat
    [foo 2 foo 1 foo 0] => fish
    [foo 2 foo 1 foo 1] => giraffe
    [foo 0] => apple
    [foo 1] => ball
)

after GOOD sort
Array
(
    [foo 2 foo 0 foo 1 foo 1] => elephant
    [foo 2 foo 0 foo 1 foo 0] => dog
    [foo 2 foo 1 foo 1] => giraffe
    [foo 2 foo 1 foo 0] => fish
    [foo 2 foo 0 foo 0] => cat
    [foo 1] => ball
    [foo 0] => apple
)

Notice the order of elephant and dog for example (or others) in two sorting methods.注意例如(或其他) elephantdog在两种排序方法中的顺序。 The second method looks better.第二种方法看起来更好。 There may be easier ways to solve this but hope this helps someone...可能有更简单的方法来解决这个问题,但希望这可以帮助某人...

Starting from an input array that resembles a sql result set, you can cleanly use usort() containing a 3-way comparison then a conditional secondary 3-way comparison.从类似于 sql 结果集的输入数组开始,您可以干净地使用包含 3 路比较的usort()然后是条件辅助 3 路比较。 When done, you can isolate the qty column of data as the values and (assuming all of the name values are unique) use the name column as the assigned keys using array_column() .完成后,您可以将数据的qty列隔离为值,并且(假设所有name值都是唯一的)使用name列作为使用array_column()的指定键。 When comparing, write the $b data on the left of the operator and the $a on the right to achieve a descending sort order.比较时,写$b左侧的操作和数据$a上实现按降序排序的权利。

Code: ( Demo )代码:(演示

$array = [
    ['name' => 'foo bar bar foo', 'qty' => 6],
    ['name' => 'bah', 'qty' => 5],
    ['name' => 'foo foo bar foo', 'qty' => 10],
    ['name' => 'foo', 'qty' => 6],
    ['name' => 'foo bar', 'qty' => 6],
    ['name' => 'bar', 'qty' => 11],
];

usort($array, function($a, $b) {
    return $b['qty'] <=> $a['qty'] ?: strlen($b['name']) <=> strlen($a['name']);
});

var_export(array_column($array, 'qty', 'name'));

Output:输出:

array (
  'bar' => 11,
  'foo foo bar foo' => 10,
  'foo bar bar foo' => 6,
  'foo bar' => 6,
  'foo' => 6,
  'bah' => 5,
)

The advantage of using comparison1 ?: comparison2 is that the function calls in comparison2 are not executed unless a tiebreak is necessary -- this improves efficiency.使用的优势comparison1 ?: comparison2的是,在函数调用comparison2不被执行,除非抢七是必要的-这提高了效率。 Alternatively, using array_multisort() will unconditionally call strlen() on all qty values -- even if they are not needed for sorting.或者,使用array_multisort()将无条件地对所有qty值调用strlen() —— 即使它们不需要进行排序。

It is perfectly valid to execute the sort with a single spaceship operator, but the following technique will make two function calls every time a comparison is made.使用单个宇宙飞船运算符执行排序是完全有效的,但每次进行比较时,以下技术将进行两次函数调用。 This will be less efficient than my above snippet, so I do not recommend the following snippet .这将比我上面的代码段效率低,所以我不推荐以下代码段

usort($array, function($a, $b) {
    return [$b['qty'], strlen($b['name']] <=> [$a['qty'], strlen($a['name'])];
});

ps Of course this can be done with array_multisort() as well, I just find the syntax to be less concise. ps 当然这也可以用array_multisort()来完成,我只是发现语法不那么简洁。

array_multisort(
    array_column($array, 'qty'),
    SORT_DESC,
    array_map(
        function($row) {
            return strlen($row['name']);
        },
        $array
    ),
    SORT_DESC,
    $array
);

var_export(array_column($array, 'qty', 'name'));

use the sort function in php.在 php 中使用 sort 函数。 make sure you use the TRUE as the second parameter to preserve the keys.确保使用 TRUE 作为第二个参数来保留密钥。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM