用PHP按子集对数组进行排序

7

I have two arrays.

One is a larger bit of data:

Array
(
    [12] => blah
    [36] => foo
    [58] => blah
    [60] => blah
    [72] => blah
    [90] => bar
)

另一个是一组不同但相关的数据,顺序不同,每个键对应于较大数组中的相同键:
Array
(
    [36] => foo data
    [90] => bar data
    [12] => blah data
)

现在,我的问题是如何使第一个数组按照顺序排列,以便与第二个数组中具有相应键的键在同一顺序下首先出现?

因此,像这样:

Array
(
    [36] => foo
    [90] => bar
    [12] => blah
    [58] => blah
    [60] => blah
    [72] => blah
)

2
我不知道,但是对于这个用户名点赞。 - Marc B
array_sort 可能适合您。 - Colum
您可能需要使用uksort,但是没有使用闭包会有一些困难。您使用的是哪个PHP版本? - Felix Kling
4个回答

5

简单的O(n)解决方案。

$arr1 = array(12 => 1, 36 => 2, 58 => 3, 60 => 4, 72 => 5);
$arr2 = array(36 => 1, 60 => 2, 12 => 1);

$result = array();

foreach($arr2 as $key => $value) {
    $result[$key] = $arr1[$key];
    unset($arr1[$key]);
}

foreach($arr1 as $key => $value) {
    $result[$key] = $arr1[$key];
}

var_dump($result);

输出:

array(5) {
  [36]=>
  int(2)
  [60]=>
  int(4)
  [12]=>
  int(1)
  [58]=>
  int(3)
  [72]=>
  int(5)
}

差不多要发布同样的内容 ;) - malko
不需要取消设置值,也不需要将所有重复项复制到另一个 for-each 中。 - hakre

2

使用uksort函数。

编辑:修复了malko指出的语法/逻辑错误。谢谢。

$array_to_sort = array
(
    12 => "blah",
    36 => "foo",
    58 => "blah",
    60 => "blah",
    72 => "blah",
    90 => "bar"
);

$sorted_array = array(
    36 => "foo data",
    90 => "bar data",
    12 => "blah data"
);

global $sorted_array_keys;
$sorted_array_keys = array_keys($sorted_array);

function cmp($a, $b)
{
    global $sorted_array_keys;
    $a_in_array = in_array($a, $sorted_array_keys);
    $b_in_array = in_array($b, $sorted_array_keys);
    if ($a_in_array && $b_in_array) {
        return array_search($a, $sorted_array_keys) - array_search($b, $sorted_array_keys);
    } else if ( $a_in_array ) {
        return -1;
    } else {
        return 1;
    }
}

uksort ( $array_to_sort , cmp );
print_r($array_to_sort);

这篇文章一开始很清晰明了,但最后变得相当丑陋和不清晰。现在我更倾向于其他答案而不是我的。


@malko - 我刚刚发布了一个示例,应该可以做到所要求的。 - Jacob Eggers
@malko 啊,我忘记了 PHP 的作用域。我通常使用有良好闭包支持的 AS3 进行工作。但是,PHP 应该可以使用全局变量。请参见编辑。 - Jacob Eggers
@jacobs,抱歉,还是不太好;) 如果您允许我评论您的代码,我会指出其中的问题。 - malko
1
@jacobs,纠正语法将导致返回:Array ( [12] => blah [90] => bar [72] => blah [58] => blah [36] => foo [60] => blah ) 这不是我们想要的结果。 - malko
@malko。是的,我已经修好并测试过了,但现在代码太丑了。在AS3中轻松得多... - Jacob Eggers
显示剩余3条评论

2

这里有一个使用闭包的uksort示例,我认为它在大型数组上应该更有效,但我没有进行任何基准测试,所以很难在没有测试的情况下真正确认。

$a = array(
    12 => 'blah'
    ,36 => 'foo'
    ,58 => 'blah'
    ,60 => 'blah'
    ,72 => 'blah'
    ,90 => 'bar'
);

$b = array(
    36 => 'foo data'
    ,90 => 'bar data'
    ,12 => 'blah data'
);

$keysPosition = array_flip(array_keys($b));
uksort($a,function($a,$b) use ($keysPosition){
    if(isset($keysPosition[$a],$keysPosition[$b])){
        return $keysPosition[$a]>$keysPosition[$b]?1:-1;
    }else if( isset($keysPosition[$a]) ){
        return -1;
    }else if( isset($keysPosition[$b]) ){
        return 1;
    }
    return 0;
});

print_r($a);

结果:

Array
(
    [36] => foo
    [90] => bar
    [12] => blah
    [72] => blah
    [58] => blah
    [60] => blah
)

如果您无法使用闭包(PHP <5.3),可以使用全局变量来实现类似的功能,但这并不干净。

1
$array1 = array(12 => 1, 36 => 2, 58 => 3, 60 => 4, 72 => 5);
$array2 = array(36 => 1, 60 => 2, 12 => 1);

# obtaining keys in the order of question    
$result = array_intersect_key($array2, $array1);

# assign values from original $array1
foreach($result as $key => &$value) {
    $value = $array1[$key];
}
unset($value); # kill reference for safety

# add missing elements from $array1
$result += $array1;

var_dump($result);

输出:

array(5) {
  [36]=>
  int(2)
  [60]=>
  int(4)
  [12]=>
  int(1)
  [58]=>
  int(3)
  [72]=>
  int(5)
}

请参见数组运算符,了解有关数组的+的更多信息。

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