【问题标题】:Sort array by two object properties using anonymous function使用匿名函数按两个对象属性对数组进行排序
【发布时间】:2012-01-25 18:00:12
【问题描述】:

我有以下数组:

Array
(
    [0] => stdClass Object
        (
            [timestamp] => 1
            [id] => 10
        )

    [1] => stdClass Object
        (
            [timestamp] => 123
            [id] => 1
        )

    [2] => stdClass Object
        (
            [timestamp] => 123
            [id] => 2
        )

) 

我目前正在使用以下代码按时间戳属性对数组进行排序:

function sort_comments_by_timestamp(&$comments, $prop)
{
    usort($comments, function($a, $b) use ($prop) {
        return $a->$prop < $b->$prop ? 1 : -1;
    });
}

当时间戳相同时,如何按id 降序对 id 进行排序?

【问题讨论】:

  • 有没有理由叫它_by_timestamp,还要有$prop参数?
  • @Matthew 除了I was doing some tests 和错误的命名?不 :) 顺便说一句已经修复了

标签: php arrays sorting


【解决方案1】:

建议是用 $props 发送数组

function sort_comments_by_timestamp(&$comments, $props)
{
    usort($comments, function($a, $b) use ($props) {
        if($a->$props[0] == $b->$props[0])
            return $a->$props[1] < $b->$props[1] ? 1 : -1;
        return $a->$props[0] < $b->$props[0] ? 1 : -1;
    });
}

然后调用它

sort_comments_by_timestamp($unsorted_array,array("timestamp","id"));

如果您希望它与 X 个 $props 一起使用,您可以在 usort 中创建一个循环,始终将一个属性与其在数组中的前一个属性进行比较,如下所示:

function sort_comments_by_timestamp(&$comments, $props)
{
    usort($comments, function($a, $b) use ($props) {
        for($i = 1; $i < count($props); $i++) {
            if($a->$props[$i-1] == $b->$props[$i-1])
                return $a->$props[$i] < $b->$props[$i] ? 1 : -1;
        }
        return $a->$props[0] < $b->$props[0] ? 1 : -1;
    });
}

干杯!

【讨论】:

  • 如果出现错误:Array to string conversion 您需要将所有$a-&gt;$props[X] 替换为$a-&gt;{$props[X]}
【解决方案2】:
function sort_comments_by_timestamp(&$comments, $prop)
{
    usort($comments, function($a, $b) use ($prop) {
        if ($a->$prop == $b->$prop)
          return $b->id - $a->id;
        else
          return $a->$prop < $b->$prop ? 1 : -1;
    });
}

上面首先按$prop 参数排序,然后按id 排序。

【讨论】:

    【解决方案3】:

    您可以使用 ouzo goodies 来实现(我知道您已经听说过:P)。

    $result = Arrays::sort($array,
        Comparator::compound(
            Comparator::compareBy('timestamp'),
            Comparator::compareBy('id')
        )
    );
    

    【讨论】:

      【解决方案4】:

      我知道这是一个相当老的问题,但是当你想按多个属性排序时没有找到太多信息,有点像 mySQL ORDERBY 这样做,这是来自个人框架的一个函数

      选项 1:order($key, $direction='asc') 其中 $key 是对象的属性,$direction 是 'asc' 或 'desc'

      选项2:order(array($key => $direction, $key => $direction)) 这类似于选项 1,但是当 2 个对象的 $key 值相同时,将使用传递的数组中的第二个排序选项。

      public function order($arr, $key=null, $direction='ASC'){
          if(!is_string($key) && !is_array($key))
              throw new InvalidArgumentException("order() expects the first parameter to be a valid key or array");
      
          $props = array();
      
          if(is_string($key)) {
              $props[$key] = strtolower($direction) == 'asc' ? 1 : -1;
          }else{
              $i = count($key);
              foreach($key as $k => $dir){
                  $props[$k] = strtolower($dir) == 'asc' ? $i : -($i);
                  $i--;
              }
          }
      
          usort($arr, function($a, $b) use ($props){
              foreach( $props as $key => $val ){
                  if( $a->$key == $b->$key ) continue;
                  return $a->$key > $b->$key ? $val : -($val);
              }
              return 0;
          });
      
          return $arr;
      
      }
      

      【讨论】:

      • 非常不错的小功能。我正在使用公认的答案来满足我的排序需求(进行了一些个人调整),它决定在网站的 CMS 更新后停止工作。这为我节省了大量时间尝试调试问题是什么。
      • 很高兴能帮上忙 :)
      【解决方案5】:
      $result = -1;
      if ($a->timestamp < $b->timestamp) {
         $result = 1;
      } else if ($a->timestamp === $b->timestamp) {
         if ($a->id < $b->id) $result = 1;
      }
      return $result;
      

      把它放在 usort 闭包中。您还可以去掉 $prop 参数和 use ($prop) 部分。

      【讨论】:

        【解决方案6】:
              function compare_city($a, $b)
              {
                // sort by state
                $retval = strnatcmp($a->state, $b->state);
                // if identical, sort by city
                if(!$retval) $retval = strnatcmp($a->city, $b->city);
                return $retval;
              }
        
              // sort alphabetically by state and city
              usort($sortable, __NAMESPACE__ . '\compare_city');
        

        这个功能对我有用!答案在:Sorting SimpleXMLElement Object arrays

        【讨论】:

        • 上面的一些答案(包括接受的答案!)似乎错过了比较的“平等”结果。很高兴看到使用 strnatcmp 来正确处理这个问题,特别是对于字符串属性。也不要忘记strnatcasecmp 不区分大小写的等效项。
        【解决方案7】:

        接受的答案有一个循环变体,并不总是有效。

        if($a->$props[$i-1] == $b->$props[$i-1])
             return $a->$props[$i] < $b->$props[$i] ? 1 : -1;
        

        obj1 prop1:foo, prop2: bar, prop3: 测试

        obj2 prop1:foo, prop2: bar, prop3: 苹果

        在 $i = 1 时,第一次比较为真,并且由于 bar 不小于 bar,它将返回 -1 而不是继续循环来评估 prop3。

        仅供参考。

        我有一个变量,它也有方向,所以每个属性也可以分别使用 -1 和 1 按升序或降序排序。

        function sortByProps(&$anArray, $props) {
            usort($anArray, function($a, $b) use ($props) {
                for($i = 0; $i < count($props); $i++) {
                    if( $a->{$props[$i][0]} < $b->{$props[$i][0]}) {
                        return $props[$i][1];
                    }
                    else if( $a->{$props[$i][0]} > $b->{$props[$i][0]}) {
                        return -1* $props[$i][1];
                    }
                }
                return 0;
            });
        }
        
        sortByProps($someArray,(array(['name',-1],['address',-1],['occupation',-1],['favorite_food',-1])));
        

        【讨论】:

          【解决方案8】:

          以下是如何按任意数量的标准进行排序,一个接一个,打破平局。它的工作原理很像 sql order by col1, col2 子句。

          我总是忘记$a - $b vs $b - $a 是升序还是降序。根据需要进行调整。

          $comparatorSequence = array(
              function($a, $b) { return $a->timestamp - $b->timestamp; }
            , function($a, $b) { return $a->id - $b->id; }
          );
          
          usort($theArray, function($a, $b) use ($comparatorSequence) {
              foreach ($comparatorSequence as $cmpFn) {
                  $diff = call_user_func($cmpFn, $a, $b);
                  if ($diff !== 0) {
                      return $diff;
                  }
              }
              return 0;
          });
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-01-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-06-16
            • 2011-09-06
            • 2012-02-20
            相关资源
            最近更新 更多