通过基于另一个数组的键对数组进行排序?


153

在PHP中可以做这样的事情吗?您将如何编写函数?这是一个例子。顺序是最重要的。

$customer['address'] = '123 fake st';
$customer['name'] = 'Tim';
$customer['dob'] = '12/08/1986';
$customer['dontSortMe'] = 'this value doesnt need to be sorted';

我想做类似的事情

$properOrderedArray = sortArrayByArray($customer, array('name', 'dob', 'address'));

因为最后我使用了foreach()并且它们的顺序不正确(因为我将值附加到需要正确顺序的字符串中,并且我事先不知道所有的数组键/值)。

我看过PHP的内部数组函数,但是看来您只能按字母或数字排序。

Answers:


347

只需使用array_merge或即可array_replaceArray_merge通过以给定的数组(按正确的顺序)开始并用实际数组中的数据覆盖/添加键来工作:

$customer['address'] = '123 fake st';
$customer['name'] = 'Tim';
$customer['dob'] = '12/08/1986';
$customer['dontSortMe'] = 'this value doesnt need to be sorted';

$properOrderedArray = array_merge(array_flip(array('name', 'dob', 'address')), $customer);
//Or:
$properOrderedArray = array_replace(array_flip(array('name', 'dob', 'address')), $customer);

//$properOrderedArray -> array('name' => 'Tim', 'address' => '123 fake st', 'dob' => '12/08/1986', 'dontSortMe' => 'this value doesnt need to be sorted')

ps-我正在回答这个“陈旧的”问题,因为我认为以前的答案给出的所有循环都是过大的。


31
如果您有字符串键,但没有数字键,它会很好地工作。PHP Docs:“如果输入数组具有相同的字符串键,则该键的后一个值将覆盖前一个键。但是,如果数组包含数字键,则后一个值将不会覆盖原始值,但将附加。”
bolbol

7
很好,但是如果键不存在于值中怎么办?我需要它,但
前提

5
就我而言,它是array_replace而不是array_merge。array_merge将两个值组合在一起,而不是将第二个数组替换为有序键。
neofreko 2014年

3
几年前,我在寻找不同的东西时偶然发现了您的解决方案-我想自己,与循环相比,这是极其有效的。现在,我需要您的解决方案,并且花了一个小时的时间才能再次找到它!谢谢!
迈克尔”

4
此外,如果'order'数组(即array('name','dob','address'))具有比要排序的数组更多的键,则结果排序后的数组与原始数组的其他array_intersect将被切断在array_merge中添加的杂散键。
bbe

105

你去了:

function sortArrayByArray(array $array, array $orderArray) {
    $ordered = array();
    foreach ($orderArray as $key) {
        if (array_key_exists($key, $array)) {
            $ordered[$key] = $array[$key];
            unset($array[$key]);
        }
    }
    return $ordered + $array;
}

12
因此,您可以使用+号连接2个数组?我从来不知道,我一直在使用array_merge()
亚历克斯

3
这比使用usort()或更好uasort()吗?
Grantwparks

5
break一旦找到值,就应该插入一条语句。
阿德尔(Adel)

4
@alex array_merge()用数组+运算符替换时要非常小心。它通过键(也适用于数字键)并从左到右array_merge合并,而从右到左合并,并且永远不会覆盖数字键。例如[0,1,2]+[0,5,6,7] = [0,1,2,7]while array_merge([0,1,2],[0,5,6,7]) = [0,1,2,0,5,6,7]['a' => 5] + ['a' => 7] = ['a' => 5]but array_merge(['a' => 5], ['a' => 7]) = ['a' => 7]
2015年

使用+标志安全吗?
crmpicco

47

这个解决方案怎么样

$order = array(1,5,2,4,3,6);

$array = array(
    1 => 'one',
    2 => 'two',
    3 => 'three',
    4 => 'four',
    5 => 'five',
    6 => 'six'
);

uksort($array, function($key1, $key2) use ($order) {
    return (array_search($key1, $order) > array_search($key2, $order));
});

1
这个需要更多的投票,其他的则不起作用/效果不佳,而在我看来,这很好。
Ng Sek Long,

这不是很有效。对于每个比较,在数组中执行两次线性搜索。如果我们假设uksort()的时间复杂度为O(n * log n),则该算法在中运行O(n^2 * log(n))
TheOperator

36

PHP> = 5.3.0的另一种方法:

$customer['address'] = '123 fake st';
$customer['name'] = 'Tim';
$customer['dob'] = '12/08/1986';
$customer['dontSortMe'] = 'this value doesnt need to be sorted';

$customerSorted = array_replace(array_flip(array('name', 'dob', 'address')), $customer);

结果:

Array (
  [name] => Tim
  [dob] => 12/08/1986
  [address] => 123 fake st
  [dontSortMe] => this value doesnt need to be sorted
)

使用字符串和数字键可以正常工作。


2
+当它们都起作用时,我发现array_replace()传达意图要比更好array_merge()
杰森·麦克雷里

1
array_replace也使变量类型保持不变。如果您数组中的某个值曾经是(string) '1'并且您曾经使用过+运算符,则该值将变成(int) 1
halfpastfour.am 2014年

1
这也适用于数字键(array_merge()是否会附加它们?)。逻辑在这里得到很好的解释。首先array_flip()将$ order数组的值更改为key。其次array_replace()用第二个数组中具有相同键的值替换第一个数组的值。如果您需要根据另一个数组中的键对数组进行排序,则甚至不必使用array_flip
aexl

23
function sortArrayByArray(array $toSort, array $sortByValuesAsKeys)
{
    $commonKeysInOrder = array_intersect_key(array_flip($sortByValuesAsKeys), $toSort);
    $commonKeysWithValue = array_intersect_key($toSort, $commonKeysInOrder);
    $sorted = array_merge($commonKeysInOrder, $commonKeysWithValue);
    return $sorted;
}

14

以一个数组作为您的订单:

$order = array('north', 'east', 'south', 'west');

您可以使用array_intersectDocs根据值对另一个数组进行排序:

/* sort by value: */
$array = array('south', 'west', 'north');
$sorted = array_intersect($order, $array);
print_r($sorted);

或者,如果您要按键排序,请使用array_intersect_keyDocs

/* sort by key: */
$array = array_flip($array);
$sorted = array_intersect_key(array_flip($order), $array);
print_r($sorted);

这两个函数都将保留第一个参数的顺序,并且只会从第二个数组返回值(或键)。

因此,对于这两种标准情况,您无需自己编写函数即可执行排序/重新排列。


交叉将摆脱那些他事先不知道的条目。
DanMan 2013年

1
按键排序不正确。array_intersect_key将仅返回array1的值,而不返回array2的值
诡异的

同意pavsid-array_intersect_key示例不正确-它从第一个数组而不是第二个数组返回值。
乔纳森·阿基诺

10

我用Darkwaltz4的解决方案,但使用array_fill_keys的替代array_flip,以填补NULL如果钥匙没有设置$array

$properOrderedArray = array_replace(array_fill_keys($keys, null), $array);

5

没有魔法...

$array=array(28=>c,4=>b,5=>a);
$seq=array(5,4,28);    
SortByKeyList($array,$seq) result: array(5=>a,4=>b,28=>c);

function sortByKeyList($array,$seq){
    $ret=array();
    if(empty($array) || empty($seq)) return false;
    foreach($seq as $key){$ret[$key]=$dataset[$key];}
    return $ret;
}

1
效果很好,谢谢,只需更新$dataset以匹配参数名称
kursus

3

如果您的数组中有数组,则必须稍微调整一下Eran的功能...

function sortArrayByArray($array,$orderArray) {
    $ordered = array();
    foreach($orderArray as $key => $value) {
        if(array_key_exists($key,$array)) {
                $ordered[$key] = $array[$key];
                unset($array[$key]);
        }
    }
    return $ordered + $array;
}

2

此函数返回基于第二个参数$ keys的子数组和排序数组

function array_sub_sort(array $values, array $keys){
    $keys = array_flip($keys);
    return array_merge(array_intersect_key($keys, $values), array_intersect_key($values, $keys));
}

例:

$array_complete = [
    'a' => 1,
    'c' => 3,
    'd' => 4,
    'e' => 5,
    'b' => 2
];

$array_sub_sorted = array_sub_sort($array_complete, ['a', 'b', 'c']);//return ['a' => 1, 'b' => 2, 'c' => 3];

1

PHP具有帮助您解决此问题的功能:

$arrayToBeSorted = array('west', 'east', 'south', 'north');
$order = array('north', 'south', 'east', 'west');

// sort array
usort($arrayToBeSorted, function($a, $b) use ($order){
    // sort using the numeric index of the second array
    $valA = array_search($a, $order);
    $valB = array_search($b, $order);

    // move items that don't match to end
    if ($valA === false)
        return -1;
    if ($valB === false)
        return 0;

    if ($valA > $valB)
        return 1;
    if ($valA < $valB)
        return -1;
    return 0;
});

Usort为您完成所有工作,array_search提供了密钥。当无法找到匹配项时,array_search()返回false,因此不在sort数组中的项目自然会移至该数组的底部。

注意:uasort()将对数组进行排序,而不会影响key => value关系。


1
  • 按要求排序
  • 保存为int键(由于array_replace)
  • 不要在inputArray中不存在键
  • (可选)给定keyList中不存在的过滤器键

码:

 /**
 * sort keys like in key list
 * filter: remove keys are not listed in keyList
 * ['c'=>'red', 'd'=>'2016-12-29'] = sortAndFilterKeys(['d'=>'2016-12-29', 'c'=>'red', 'a'=>3 ]], ['c', 'd', 'z']){
 *
 * @param array $inputArray
 * @param string[]|int[] $keyList
 * @param bool $removeUnknownKeys
 * @return array
 */
static public function sortAndFilterKeys($inputArray, $keyList, $removeUnknownKeys=true){
    $keysAsKeys = array_flip($keyList);
    $result = array_replace($keysAsKeys, $inputArray); // result = sorted keys + values from input + 
    $result = array_intersect_key($result, $inputArray); // remove keys are not existing in inputArray 
    if( $removeUnknownKeys ){
        $result = array_intersect_key($result, $keysAsKeys); // remove keys are not existing in keyList 
    }
    return $result;
}

1

第一个建议

function sortArrayByArray($array,$orderArray) {
    $ordered = array();
    foreach($orderArray as $key) {
        if(array_key_exists($key,$array)) {
            $ordered[$key] = $array[$key];
            unset($array[$key]);
        }
    }
    return $ordered + $array;
}

第二建议

$properOrderedArray = array_merge(array_flip(array('name', 'dob', 'address')), $customer);

我想指出,这两个建议都很棒。但是,它们是苹果和橙子。区别?一个是非关联友好,另一个是关联友好。如果使用2个完全关联的数组,则数组merge / flip实际上将合并并覆盖另一个关联的数组。就我而言,这不是我想要的结果。我使用settings.ini文件来创建我的排序顺序数组。我正在排序的数据数组不需要由我的关联排序对象覆盖。因此,数组合并会破坏我的数据数组。两者都是很好的方法,都需要保存在任何开发人员工具箱中。根据您的需求,您可能会发现实际上需要在归档中同时使用这两个概念。


1

我采用了@ Darkwaltz4的简洁性答案,并希望分享我如何将解决方案适应于数组可能为每次迭代包含不同键的情况,例如:

Array[0] ...
['dob'] = '12/08/1986';
['some_key'] = 'some value';

Array[1] ...
['dob'] = '12/08/1986';

Array[2] ...
['dob'] = '12/08/1986';
['some_key'] = 'some other value';

并维护“主密钥”,如下所示:

$master_key = array( 'dob' => ' ' ,  'some_key' => ' ' );

array_merge将基于$ master_key在Array [1]迭代中执行合并,并为该迭代产生['some_key'] =”(空值)。因此,在每次迭代中都使用array_intersect_key修改$ master_key,如下所示:

foreach ($customer as $customer) {
  $modified_key = array_intersect_key($master_key, $unordered_array);
  $properOrderedArray = array_merge($modified_key, $customer);
}

0

有点晚了,但是我找不到实现它的方式,这个版本需要关闭,php> = 5.3,但是可以更改为:

$customer['address'] = '123 fake st';
$customer['name'] = 'Tim';
$customer['dob'] = '12/08/1986';
$customer['dontSortMe'] = 'this value doesnt need to be sorted';

$order = array('name', 'dob', 'address');

$keys= array_flip($order);
uksort($customer, function($a, $b)use($keys){
    return $keys[$a] - $keys[$b];
});
print_r($customer);

当然,“ dontSortMe”需要进行整理,并且可能在示例中首先出现

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.