簡體   English   中英

按列值 DESC 對多維數組進行排序,然后按另一列 DESC 的長度排序

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

我需要對一些不是來自數據庫但結構類似於 sql 結果集的數據進行排序。

在 MySQL 中,我將編寫如下查詢以按兩列對數據進行排序:

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

但是,在這種情況下,我需要使用 php 執行此排序邏輯。 具體來說,行首先按qty降序排序,然后按name的長度降序排序。

未排序的輸入:

[
    ['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],
]

排序后,我需要使用name值作為鍵, qty值作為平面關聯數組的值重構數據 完成的數組將如下所示:

期望輸出:

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

看看 php 的usortuasort

您應該能夠定義一個可以像這樣對其進行排序的函數

不確定它是否可以輕松地與當前陣列一起使用,但它會

$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;
}

查看這個問題的答案: PHP array multiple sort - by value then by key? ,看來array_multisort是要走的路。 (我不太確定array_multisort是如何工作的,我只是稍微修改了一下,它似乎有效)。

試試這個:

$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);

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

更新:添加了array_map以使其按字符串的長度排序,然后才執行:

$str1 > $str2而不是strlen($str1) > strlen($str2)

更新 2:在 PHP >= 5.3 中,您可以用真正的匿名函數替換create_function

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

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

根據長度對鍵進行排序時的一個限制是:不重新排序等長鍵。 假設我們需要按長度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/>";
}

輸出將是:

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
)

注意例如(或其他) elephantdog在兩種排序方法中的順序。 第二種方法看起來更好。 可能有更簡單的方法來解決這個問題,但希望這可以幫助某人...

從類似於 sql 結果集的輸入數組開始,您可以干凈地使用包含 3 路比較的usort()然后是條件輔助 3 路比較。 完成后,您可以將數據的qty列隔離為值,並且(假設所有name值都是唯一的)使用name列作為使用array_column()的指定鍵。 比較時,寫$b左側的操作和數據$a上實現按降序排序的權利。

代碼:(演示

$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'));

輸出:

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

使用的優勢comparison1 ?: comparison2的是,在函數調用comparison2不被執行,除非搶七是必要的-這提高了效率。 或者,使用array_multisort()將無條件地對所有qty值調用strlen() —— 即使它們不需要進行排序。

使用單個宇宙飛船運算符執行排序是完全有效的,但每次進行比較時,以下技術將進行兩次函數調用。 這將比我上面的代碼段效率低,所以我不推薦以下代碼段

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

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'));

在 php 中使用 sort 函數。 確保使用 TRUE 作為第二個參數來保留密鑰。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM