如何使用飞船运算符按两个值对多维数组排序?

时间:2018-12-19 16:46:44

标签: php arrays sorting spaceship-operator

我正在尝试使用飞船运算符对多维数组进行排序。

<?php

$my_array = [

    ['name'=>'cool', 'volume'=> 2, 'page'=>1],
    ['name'=>'sonic', 'volume'=> 1, 'page'=>1],
    ['name'=>'tails', 'volume'=> 3, 'page'=>1],
    ['name'=>'knuckles', 'volume'=> 1, 'page'=>2],
    ['name'=>'amy', 'volume'=> 1, 'page'=>3],
    ['name'=>'charmy', 'volume'=> 0, 'page'=>1]

];

usort($my_array, function ($a, $b) {
        return $a['page'] <=> $b['page'];
    });

var_dump($my_array);

我只能使用一个值进行比较,但是如何使用两个值(数量和页面)进行排序?

4 个答案:

答案 0 :(得分:0)

如果必须使用usort(),则可以这样做:

<?php

$my_array = [

    ['name'=>'cool', 'volume'=> 2, 'page'=>1],
    ['name'=>'cool', 'volume'=> 1, 'page'=>1],
    ['name'=>'cool', 'volume'=> 3, 'page'=>1],
    ['name'=>'cool', 'volume'=> 1, 'page'=>2],
    ['name'=>'cool', 'volume'=> 1, 'page'=>3],
    ['name'=>'cool', 'volume'=> 0, 'page'=>1]

];

usort($my_array, function ($a, $b) {
    $return = $a['page'] <=> $b['page'];
    return ( !$return ? $a['volume'] <=> $b['volume'] : $return );
});

var_dump($my_array);

我尚未对此进行测试,并且您没有提供所需输出的样本,因此您可能需要进行修改以适合您的需求。

https://www.the-art-of-web.com/php/sortarray/#section_3有很多很棒的分类工具。

答案 1 :(得分:0)

不是您的问题的答案,但我通常会这样做,例如:

array_multisort(array_column($my_array, 'page'),
                array_column($my_array, 'volume'), SORT_DESC, $my_array);

答案 2 :(得分:0)

<?php

$my_array = [

    ['name'=>'cool', 'volume'=> 2, 'page'=>1],
    ['name'=>'cool', 'volume'=> 1, 'page'=>1],
    ['name'=>'cool', 'volume'=> 3, 'page'=>1],
    ['name'=>'cool', 'volume'=> 1, 'page'=>2],
    ['name'=>'cool', 'volume'=> 1, 'page'=>3],
    ['name'=>'cool', 'volume'=> 0, 'page'=>1]

];

usort($my_array, function ($a, $b) {
    $page = $a['page'] <=> $b['page'];
    $volume = $a['volume'] <=> $b['volume'];
    if(0 == $page){
        return $volume;
    }else{
        return $page;
    }
});

var_dump($my_array);

答案 3 :(得分:-1)

介绍函数式编程的一种有趣方式-

# main.php

require 'comparison.php';

function sortByPage ($a, $b) {
  return $a['page'] <=> $b['page'];
}

function sortByVolume ($a, $b) {
  return $a['volume'] <=> $b['volume'];
}

// first sort by volume, then sort by page
usort($my_array, \comparison\concat (sortByVolume, sortByPage));

concat上方可能不是很直观。当然,您concat已经使用了两个字符串或两个数组,甚至可以考虑将1 + 2之类的数字添加为concat (1, 2)。但是concat两个功能是什么样子?

当您concat两个字符串时,结果是一个字符串。当concat两个数组时,结果是一个数组。当您concat使用两个比较函数时,结果将是另一个比较函数。

# comparison.php

namespace comparison;

require 'ordered.php';

function concat ($c1, $c2) {
  return function ($a, $b) use ($c1, $c2) {
    return \ordered\concat
      ( $c1 ($a, $b)
      , $c2 ($a, $b)
      );
  };
}

比较函数需要两个参数,并且必须返回 ordered 结果(-1、0或1)。但是,就像我们可以为比较功能实现concat一样,我们也可以为有序结果实现concat。因此,我们将$a$b传递给每个比较函数$c1$c1,每个都产生一个 ordered 值。最终结果是两个有序值的concat

那么当您concat两个有序值时会发生什么呢?您将获得另一个订购价值!

// ordered.php

namespace ordered;

function concat ($a, $b) {
  return $a === 0 ? $b : $a;
}

以上是获得所需结果所需要的,但是某些决定可能会让人感到任意。也许您还觉得必须将sortByPagesortByVolume定义为单独的函数很繁琐。也许您还需要具有反向排序的功能,这意味着甚至定义更多函数。或者,也许您需要使用 more 而不是两个排序功能进行排序。扩展我们的comparisonordered模块将有所帮助。

ordered.php

PHP传统上使用-1、0和1来编码有序结果。我们可以在模块中对此进行更明确的说明。请注意,每个功能都很简单,就像一两个功能一样。

namespace ordered;

const eq = 0;
const gt = 1;
const lt = -1;

function concat ($a, $b) {
  return $a === eq ? $b : $a;
}

function sum ($os) {
  return array_reduce ($os, '\ordered\concat', eq);
}

function reverse ($a) {
  return $a * -1;
}

comparison.php

在此模块中,我们将<=>实现为函数compare而不是运算符。请注意,我们还返回了有序的ltgteq而不是-1、1或0。这尊重了抽象障碍,并允许 ordered 模块更改其表示形式而不会影响比较模块。再次强调,每个函数只能执行一两件事。

namespace comparison;

require 'ordered.php';

function compare ($a, $b) {
  if ($a < $b)
    return \ordered\lt; // respect abstraction barrier
  if ($a > $b)
    return \ordered\gt; // respect abstraction barrier
  else
    return \ordered\eq; // respect abstraction barrier
}

function concat ($c1, $c2) {
  return function ($a, $b) use ($c1, $c2) {
    return \ordered\concat // respect abstraction barrier
      ( $c1 ($a, $b)
      , $c2 ($a, $b)
      );
  };
}

function sum ($cs) {
  return array_reduce ($cs, '\comparison\concat', '\comparison\compare');
}

function reverse ($c) {
  return function ($a, $b) use ($c) {
    return \ordered\reverse ($c ($a, $b)); // respect abstraction barrier
  };
}

function contramap ($f, $g) {
  return function ($a, $b) use ($f, $g) {
    return $f
      ( $g ($a)
      , $g ($b)
      );
  };
}

这些简单的模块几乎适合于任何排序任务。

1。。组合任意数量的分拣器

// possibly based on form submission data
$sorters =
  [ 'sortByVolume'  // pre-defined function
  , 'sortByPage'    // pre-defined function
  , 'sortByName'    // pre-defined function
  ];

usort ($my_array, \comparison\sum ($sorters));

2。反向排序

usort ($my_array, \comparison\reverse ('sortByVolume'));

3。。匿名分类器-无需定义sortByVolumesortByPage等。

function sortBy ($key) {
  return \comparison\contramap
    ( '\comparison\compare'
    , function ($x) use ($key) { return $x[$key]; }
    );
}

usort
  ( $my_array
  , \comparison\concat
      ( sortBy ('volume') // sorter created ad hoc
      , sortBy ('page')   // same here
      )
  );

4。。能够混合和匹配这些效果并产生可靠的结果是功能编程的不可否认的优势。

$sorters =
  [ 'sortByVolume',            // pre-defined function
  , sortBy ('page')            // anonymous sorter
  , reverse (sortBy ('name'))  // reverse sorter
  ];

usort
  ( $my_array
  , \comparison\sum ($sorters) // combine all sorters
  );

最后,我们没有在模块中使用太空飞船运营商<=>。函数式编程完全是关于使用函数进行编程的,因此避免使用诸如简单语句之类的语句,关键字和运算符。这样做的原因是因为可以轻松地使用组合功能来组合功能,而语句和运算符却无法始终组合。

相关问题