【问题标题】:Sort array based on key => value pair根据键 => 值对对数组进行排序
【发布时间】:2015-12-02 14:07:58
【问题描述】:

我正在尝试根据key=>value 对数组进行排序,但我无法完成此操作。这是我正在编写的代码:

$arr = [
    '183034' => 9,
    '183033' => 6,
    '183032' => 3,
    '183002' => null,
    '182973' => null,
    '182971' => null,
    '182969' => null,
    '182999' => null,
    '182997' => null,
    '182995' => null,
    '182962' => null,
    '182948' => null
];

$arrTemp = [];

foreach($arr as $key => $value) {
    $arrTemp[$key] = $value;
}

array_multisort($arrTemp, SORT_NUMERIC, $arr);

var_export($arrTemp);

输出是:

#php test.php
array (
  0 => NULL,
  1 => NULL,
  2 => NULL,
  3 => NULL,
  4 => NULL,
  5 => NULL,
  6 => NULL,
  7 => NULL,
  8 => NULL,
  9 => 3,
  10 => 6,
  11 => 9,
)

但我希望是这样的:

array (
    '183002' => null,
    '182973' => null,
    '182971' => null,
    '183032' => 3,
    '182969' => null,
    '182999' => null,
    '183033' => 6,
    '182997' => null,
    '182995' => null,
    '183034' => 9,
    '182962' => null,
    '182948' => null    
);

where value 定义了项目应该移动的位置。换句话说,让我们举个例子:'183032' => 3 这个项目在结果数组上保持位置 3,所以我应该做的是保持相同的数组顺序,但将该项目移动到位置 3,正如您在输出数组上可能注意到的那样。 '183033' => 6 也是如此,其中这个持有位置 6,所以我重新排列整个数组以将其移动到位置 6,依此类推。有谁能帮帮我吗?

更新

如果我把原来的$arr改成这样:

$arr = [
    '183034' => ['sort_position' => 9],
    '183033' => ['sort_position' => 5],
    '183032' => ['sort_position' => 3],
    '183002' => [],
    '182973' => [],
    '182971' => [],
    '182969' => [],
    '182999' => [],
    '182997' => [],
    '182995' => [],
    '182962' => [],
    '182948' => []
];

几乎相同,但这就是数组的外观(只是一个示例),带有[] 的数组内部应该有其他键我只是不在这里写它们,因为相关的是sort_position

【问题讨论】:

  • 试试php.net,非常棒:)
  • 也许SORT_DESC | SORT_NUMERIC ??
  • 你能解释一下输出吗,你想要。
  • @DamienPirsy 所需的输出键不是ASC的顺序
  • 你试过简单的krsort()

标签: php arrays algorithm sorting


【解决方案1】:
$arr = [
    '183034' => ['sort_position' => 9],
    '183033' => ['sort_position' => 5],
    '183032' => ['sort_position' => 3],
    '183002' => [],
    '182973' => [],
    '182971' => [],
    '182969' => [],
    '182999' => [],
    '182997' => [],
    '182995' => [],
    '182962' => [],
    '182948' => []
];
$count = count($arr);
$tmp=[];
//sort by key descending
krsort($arr);
foreach($arr as $key=>$val){
    //if element has a sort position
    if(isset($val['sort_position'])){
        //save it in tmp, indexed by sort position
        $tmp[$val['sort_position']]=$val;
        //and remove it from original array
        unset($arr[$key]);
    }
}
//Note $arr now only contains elements without sort position

$out=[];
//build new array of same length as original
for($i=0; $i < $count; $i++){
    //if there is an element in temp with this sort position, use it
    //else grab the next one from the non sort position elements
    $out[] = isset($tmp[$i])? $tmp[$i] : array_shift($arr);
}

var_dump($out);

编辑刚刚意识到我错过了数组键的重要性。也许你实际上并不需要密钥,但为了完整起见,这里有一个修改后的解决方案,它也保留了密钥:

$count = count($arr);
$has_sortorder=[];
$no_sortorder=[];
krsort($arr);
foreach($arr as $key=>$val){
    if(isset($val['sort_position'])){
        $has_sortorder[$val['sort_position']]=[$key, $val];
    }else{
        $no_sortorder[]=[$key, $val];
    }
}


$out=[];
for($i=0; $i < $count; $i++){
    if(isset($has_sortorder[$i])){
        $out[$has_sortorder[$i][0]] = $has_sortorder[$i][1];
    }else{
        $element = array_shift($no_sortorder);
        $out[$element[0]] = $element[1];
    }
}

var_dump($out);

【讨论】:

  • 谢谢,这是我正在寻找的更接近的地方,这个帮助和 cmets,简直太好了
【解决方案2】:

恕我直言,这不是排序问题,因为您有多个无法排序的元素(空值应保持在同一位置,位于数组的开头或结尾)。

您的问题与某些元素在正确位置的定位有关。 我认为您应该通过遍历数组来解决它。

【讨论】:

    【解决方案3】:

    让我们试试这个

    http://sandbox.onlinephpfunctions.com/code/f72cc2ef661f805a9f5a8a491c2cf5455ed31c60

    $arr = array(
        '183034' => 9,
        '183033' => 6,
        '183032' => 3,
        '183002' => null,
        '182973' => null,
        '182971' => null,
        '182969' => null,
        '182999' => null,
        '182997' => 10,
        '182995' => null,
        '182962' => null,
        '182948' => null
    );
    
    // sort by value and maintaiming key value association
    // separate null values from numeric values
    // null values a start of array 
    // numeric values at end of array
    asort($arr, SORT_NATURAL);
    
    
    
    // this is a temporary array used to store every single row from $arr
    // as a array value
    // the keys of this array start with 0 and are positional
    $arrTemp = [];
    
       
    foreach ( $arr as $key => $value ) {
      if ( is_numeric($value) ) {
        // insert into $arrTemp the numeric value at the correct position
        // because we arsorted $arr before, the splice does not push
        // numeric values behind
        array_splice($arrTemp, $value, 0, array(array($key => $value)));
      } else {
        // these are the null values, they fill up the start of $arrTemp
        $arrTemp[] = array($key => $value);
      }
    }
    
    $arrOut = array();
    
    
    // get the array of arrays back into a hash array
    foreach ( $arrTemp as $value ) {
      list($key, $val) = each($value);
      $arrOut[$key] = $val;
    }
    
    print_r($arrOut);
    

    编辑

    从 OP 更改规格后,将是这个解决方案

    http://sandbox.onlinephpfunctions.com/code/f72cc2ef661f805a9f5a8a491c2cf5455ed31c60

    $arr = array(
        '183034' => array('sort_position' => 9),
        '183033' => array('sort_position' => 5),
        '183032' => array('sort_position' => 3),
        '183002' => array(),
        '182973' => array(),
        '182971' => array(),
        '182969' => array(),
        '182999' => array(),
        '182997' => array(),
        '182995' => array(),
        '182962' => array(),
        '182948' => array(),
    );
    
    $arrTemp = [];
    
    uasort($arr, 'compare_function');
    
    
    foreach ( $arr as $key => $value ) {
      if ( !empty($value) && is_numeric($value['sort_position']) ) {
        array_splice($arrTemp, $value['sort_position'], 0, array(array($key => $value)));
      } else {
        $arrTemp[] = array($key => $value);
      }
    }
    
    $arrOut = array();
    
    foreach ( $arrTemp as $value ) {
      list($key, $val) = each($value);
      $arrOut[$key] = $val;
    }
    
    print_r($arrOut);
    
    
    function compare_function($a, $b) {
        if ( isset($a['sort_position']) && !isset($b['sort_position']) ) {
            return 1;
        }
        if ( isset($b['sort_position']) && !isset($a['sort_position']) ) {
            return -1;
        }
        if ( isset($a['sort_position']) && isset($b['sort_position']) ) {
            if ( (int) $a['sort_position'] == (int) $b['sort_position']  ) {
                return 0;
            }
            return (int) $a['sort_position'] < (int) $b['sort_position'] ? -1 : 1;
        }
    
    }
    

    【讨论】:

    • 太好了,这正是我要找的,谢谢,现在让我学习你的解决方案
    • 你能根据我的更新更新你的代码吗?您的代码仍在使用第一种方法,我将很快放弃它
    猜你喜欢
    • 2013-05-14
    • 2017-09-29
    • 2011-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-25
    • 2016-05-12
    相关资源
    最近更新 更多