基于另一个数组对 PHP 数组进行排序?

17

好的,我在stackoverflow上已经看到了这个问题,但是不幸的是它是用JavaScript写的 - Javascript - sort array based on another array

而我想要的是用PHP实现

$data = array(
   "item1"=>"1",
   "item2"=>"3",
   "item3"=>"5",
   "item4"=>"2",
   "item5"=>"4"
);

使此数组的排列匹配:

sortingArr = array("5","4","3","2","1");

我需要的输出结果:

$data = array(
    "item3"=>"5",
    "item5"=>"4",
    "item2"=>"3",
    "item4"=>"2",
    "item1"=>"1"
 );

有什么想法可以完成这个吗? 谢谢。


你可以对它们都使用 asort() - Albzi
使用 usort() 函数,其中包含一个比较函数,用于比较 $sortingArr 中值的位置。 - Barmar
9个回答

13

要获得有关为什么array_multisort不符合您的需求的详细答案,请查看此答案: PHP array_multisort不按预期对我的多维数组进行排序

简而言之:您想根据预定义顺序对数组进行排序。答案也在那里给出,但我也将一个解决方案复制到了这个答案中:

使用usortarray_flip,这样您就可以将您的索引数组(ValueByPosition)转换为PositionByValue数组。

    $data = array(
   "item1"=>"1",
   "item2"=>"3",
   "item3"=>"5",
   "item4"=>"2",
   "item5"=>"4"
);

usort($data, "sortByPredefinedOrder");

function sortByPredefinedOrder($leftItem, $rightItem){
  $order = array("5","4","3","2","1");

  $flipped = array_flip($order);

  $leftPos = $flipped[$leftItem];
  $rightPos = $flipped[$rightItem];
  return $leftPos >= $rightPos;   
}

print_r($data);
// usort: Array ( [0] => 5 [1] => 4 [2] => 3 [3] => 2 [4] => 1 )
// uasort: Array ( [item3] => 5 [item5] => 4 [item2] => 3 [item4] => 2 [item1] => 1 )

但是这将需要你预测预定义顺序数组中的所有可能项,或以适当方式排列其他项。

如果您想保留关联键,请使用uasort而不是usort


10

相当简单吧?

$data = array(
   "item1"=>"1",
   "item2"=>"3",
   "item3"=>"5",
   "item4"=>"2",
   "item5"=>"4"
);

$sortingArr = array("5","4","3","2","1");

$result = array(); // result array
foreach($sortingArr as $val){ // loop
    $result[array_search($val, $data)] = $val; // adding values
}
print_r($result); // print results

输出:

Array
(
    [item3] => 5
    [item5] => 4
    [item2] => 3
    [item4] => 2
    [item1] => 1
)

2
我认为这不是一个很好的内存高效解决方案。在这种情况下,usort函数更容易、更快速。但对于小数组来说,这仍然是一个可行的解决方案。敬礼。 - Jacek Kowalewski
1
只要这不是在应用程序的关键部分完成,并且数据相对较小,它将以易于理解的方式完成其工作。 - flu

2

使用usort()函数以正确的方式排序,我认为:

使用用户自定义比较函数按值对数组进行排序。

您可以按以下方式操作:

$data = array(
   "item1"=>"1",
   "item2"=>"3",
   "item3"=>"5",
   "item4"=>"2",
   "item5"=>"4"
);

$sortingArr = array("5","4","3","2","1");

$keys = array_flip($sortingArr);

usort($data, function ($a, $b) use ($keys) {
    return $keys[$a] > $keys[$b] ? 1 : -1;
});

print_r($data);

// Output
// Array ( [0] => 5 [1] => 4 [2] => 3 [3] => 2 [4] => 1 )

实例演示: https://3v4l.org/75cnu


1

我对我的解决方案感到非常自豪:

uasort($data, function($a, $b) use ($sortingArr) {  
    return array_search($a, $sortingArr) <=> array_search($b, $sortingArr);
});

工作示例:https://3v4l.org/bbIk2

  1. 它使用uasort来维护键值关联,就像OP请求的那样。(与@hassan的优雅解决方案不同)
  2. 它不要求排序数组中的每个元素都存在于$data数组中。(像@HamZa的解决方案一样)
  3. 很简短。
  4. 它使用太空船运算符<=>进行比较,而不是更冗长的逻辑。

代码:


1

查看代码片段以使一个多维数组按输入顺序排序

$input_format_list = [4, 1];
$data = array(
    "0" => array(
        "School" => array(
            "id" => 1,
             "name" => "ST.ANN'S HIGH SCHOOL",
        )
    ),     
    "1" => array(
        "School" => array(
            "id" => 4,
            "name" => "JYOTI VIDHYA VIHAR",
        )
    )
);   

$result = array(); // result array
foreach($input_format_list as $key => $value){ // loop
    foreach ($data as $k => $val) {
        if ($data[$k]['School']['id'] === $value) {
           $result[$key] = $data[$k];
        }
    }            
}            
return $result;

1
看一下我接下来的代码片段,可以根据另一个数组对你的数组进行排序:
$res_arr = array(); 
for ($i = 0; $i < count($sortingArr); $i++) {
     for ($j = 0; $j < count($data); $j++) {
          if($data[$j] == $sortingArr[$i]) {
             $res_arr[] = $data[$j];
             break;
          }
     }
}
// $res_array is your sorted array now

这有点晚了,但是为什么你在结尾使用 break? - Wanjia
当找到相应的条目时,break停止内部循环的进一步迭代。它可以不用,但您可以节省一些额外的内部循环迭代。 - alex
1
只有在您确定每种类型都有一个值时,才需要使用break语句,对吗? - Wanjia
是的,正确的。很好的观点,所以如果您有多个相同点的项目,您必须删除break。 - alex

0
<?php 
$data = array(
   "item1"=>"1",
   "item2"=>"3",
   "item3"=>"5",
   "item4"=>"2",
   "item5"=>"4"
);
$result=array_flip($data);

krsort($result);

$result=array_flip($result);

print_r($result);

//use rsort for the index array

$sortingArr = array("5","4","3","2","1");

print_r($sortingArr);

1
按值对$data的值进行排序并没有意义,因为$sortingArr可能不是降序排列的。而且使用array_flip然后再使用krsort只会让代码变得丑陋,你可以直接使用rsort - HamZa
$sortingArr也通过使用rsort按降序排序。现在两个数组都以降序可用。 - Sundar

0
进一步扩展安德鲁的回答,如果你希望排序数组中的未定义条目出现在输出数组的末尾:
uasort($currentTags, function ($a, $b) use ($sortingArr) {
    if (in_array($a, $sortingArr) && !in_array($b, $sortingArr)) return -1;
    if (!in_array($a, $sortingArr) && in_array($b, $sortingArr)) return 1;
    if (!in_array($b, $sortingArr)) return -1;
    return array_search($a, $sortingArr) <=> array_search($b, $sortingArr);
});

0

看一下array_multisort。我不是完全确定如何使用它,因为我从未找到过实际用途(我更喜欢使用usort来清晰地定义我的术语),但它可能适合你。


1
我认为array_multisort()并不是他所需要的。它会正常地对一个数组进行排序,然后相应地重新排列另一个数组。 - Barmar
所以如果第一个数组是包含所需顺序的那个,那么将 $data 数组作为第二个数组排序,这难道不意味着它会相应地进行排序吗?我不知道,就像我说的,从未使用过那个函数! - Niet the Dark Absol
我也没有使用过它,但是文档页面上的示例似乎与他想要的不符。看看示例#1。它不保留任何一个输入的原始顺序。 - Barmar
我曾经用它来根据用户输入对表格进行排序,这确实是一个奇怪的函数,但有时很有用。我可以发布一个示例,但恐怕与您的问题没有直接关系。 - Dave
看一下我的帖子,了解数组多重排序的工作原理。不会的。array_multisort将“排序”数组,定义顺序并相对地向上或向下移动其他数组的条目。这不是这里所需要的。 - dognose
我认为这对我起作用了:array_multisort($sortingArr, SORT_ASC, $data, SORT_ASC); - Hayden Thring

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接