开发者

PHP sort array by subset

开发者 https://www.devze.com 2023-03-16 05:27 出处:网络
I have two arrays. One is a larger bit of data: Array ( [12] => blah [36] => foo [58] => blah [60] =>开发者_JS百科; blah

I have two arrays.

One is a larger bit of data:

Array
(
    [12] => blah
    [36] => foo
    [58] => blah
    [60] =>开发者_JS百科; blah
    [72] => blah
    [90] => bar
)

The other is a smaller subset of different but related data in a different order, with each key corresponding to the same key in the larger array:

Array
(
    [36] => foo data
    [90] => bar data
    [12] => blah data
)

Now, my question is, how do I get the first array to be in such an order so that the keys in the first array that have corresponding keys in the second array will appear first and in the same order as the second array?

Thus, like this:

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


Simple O(n) solution.

$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);

Output:

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


Here's an example using uksort with closure, it should be more effective on big array i think, but i haven't done any benchmark so... difficult to really confirm w/o test.

$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);

result:

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

If you can't use closure (php <5.3) you can do something similar using a global but it's not clean at all.


use uksort

edit: fixed syntax/logic errors pointed out by malko. thank you.

$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);

This started off nice and clean, but ended up pretty ugly and unclear. I now I'm leaning toward some of the other answers rather than mine.


$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);

Output:

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

See Array Operators for the + for arrays.

0

精彩评论

暂无评论...
验证码 换一张
取 消