別の配列に基づいて配列をキーでソートしますか?


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の内部配列関数を調べましたが、アルファベット順または数値順でしかソートできないようです。

回答:


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ドキュメント:「入力配列に同じ文字列キーがある場合、そのキーの新しい値は以前のキーを上書きします。ただし、配列に数値キーが含まれている場合、新しい値は元の値を上書きしませんが、添付。"
bolbol

7
いいですが、キーが値に存在しない場合はどうなりますか?私はこれが必要ですが、キーのいずれかが存在する場合に限ります。おそらく、そのためのforeachが必要です...
Solomon Closson

5
私の場合、それはarray_mergeではなくarray_replaceです。array_mergeは、2番目の配列を順序付けられたキーに置き換える代わりに、両方の値を組み合わせます。
neofreko 2014年

3
数年前に別の何かを探しているときに私はあなたの解決策を偶然見つけました-そして私は自分で考えました、これはループに比べて非常に効率的です。さて、私はあなたの解決策を必要としています、そしてそれを再び見つけるために私を探すのに1時間かかりました!ありがとう!
マイケル、

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 2009

5
break値が見つかったら、ステートメントを挿入する必要があります。
アデル、

4
@alex array_merge()配列+演算子で置き換えるときは注意してください。これはキー(数字キーの場合も)と左から右array_mergeマージされますが右から左にマージされ、数字キーを上書きすることありません。たとえば[0,1,2]+[0,5,6,7] = [0,1,2,7]、ながらarray_merge([0,1,2],[0,5,6,7]) = [0,1,2,0,5,6,7]['a' => 5] + ['a' => 7] = ['a' => 5]しかし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

これはあまり効率的ではありません。すべての比較について、配列内の2つの線形検索が実行されます。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()ます。
Jason McCreary、2014

1
array_replace変数の型もそのままにします。配列内のいずれかの値(string) '1'がそのままで、+演算子を使用した場合、値は次のようになります(int) 1
halfpastfour.am

1
これは数値キーでも機能します(array_merge()追加するだけですか?)。ロジックはここで非常によく説明されています最初array_flip()、$ order配列の値をキーに変更します。次にarray_replace()最初の配列の値を、2番目の配列で同じキーを持つ値に置き換えます。別のキーに基づいて配列をソートする必要がある場合は、を使用する必要さえありません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

1つの配列を注文として受け取ります。

$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_keyドキュメントを使用します:

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

どちらの関数も最初のパラメーターの順序を保持し、2番目の配列から値(またはキー)のみを返します。

したがって、これらの2つの標準的なケースでは、並べ替え/再配置を実行するために独自に関数を記述する必要はありません。


交差は、事前に知らないエントリを削除します。
DanMan 2013年

1
これは、キーによるソートでは正しくありません。array_intersect_keyは、array2からではなく、array1からの値のみを返します
不気味な

pavsidに同意-array_intersect_keyの例は正しくありません-2番目ではなく最初の配列から値を返します。
ジョナサンアキノ

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
いきました。

3

配列に配列がある場合は、エランによる関数を少し調整する必要があります...

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

この関数は、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を返すため、並べ替え配列にない項目は当然配列の最後に移動します。

注:uasort()は、キー=>値の関係に影響を与えずに配列を並べ替えます。


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;
}

2番目の提案

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

私はこれらの提案の両方が素晴らしいことを指摘したかったのです。ただし、リンゴとオレンジです。違い?1つは非連想的で、もう1つは連想的です。2つの完全な連想配列を使用している場合、配列のマージ/フリップは実際には他の連想配列をマージして上書きします。私の場合、それは私が探していた結果ではありません。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'はソートする必要があり、例の最初に表示される場合があります

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.