Mengurutkan Array berdasarkan kunci berdasarkan pada Array lain?

153

Apakah mungkin dalam PHP untuk melakukan hal seperti ini? Bagaimana Anda akan menulis fungsi? Berikut ini sebuah contoh. Urutan adalah hal yang paling penting.

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

Dan saya ingin melakukan sesuatu seperti

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

Karena pada akhirnya saya menggunakan foreach () dan mereka tidak dalam urutan yang benar (karena saya menambahkan nilai ke string yang harus dalam urutan yang benar dan saya tidak tahu sebelumnya semua kunci array / nilai).

Saya telah melihat melalui fungsi array internal PHP tetapi tampaknya Anda hanya dapat mengurutkan berdasarkan abjad atau angka.

alex
sumber

Jawaban:

347

Cukup gunakan array_mergeatau array_replace. Array_mergebekerja dengan memulai dengan array yang Anda berikan (dalam urutan yang tepat) dan menimpa / menambahkan kunci dengan data dari array aktual Anda:

$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 - Saya menjawab pertanyaan 'basi' ini, karena saya pikir semua loop yang diberikan sebagai jawaban sebelumnya terlalu banyak.

Darkwaltz4
sumber
31
Ini berfungsi dengan baik jika Anda memiliki kunci string tetapi tidak untuk yang numerik. PHP Documents: "Jika array input memiliki kunci string yang sama, maka nilai nanti untuk kunci itu akan menimpa yang sebelumnya. Jika, bagaimanapun, array berisi kunci numerik, nilai kemudian tidak akan menimpa nilai asli, tetapi akan menjadi ditambahkan. "
bolbol
7
Bagus, tetapi bagaimana jika kunci tidak ada dalam nilai? Saya membutuhkan ini, tetapi hanya jika ada kunci yang ada ... Mungkin perlu mengetahui terlebih dahulu ...
Solomon Closson
5
untuk kasus saya ini array_replace bukan array_merge. array_merge menggabungkan kedua nilai alih-alih mengganti array kedua ke kunci yang dipesan.
neofreko
3
Saya menemukan solusi Anda beberapa tahun yang lalu ketika mencari sesuatu yang berbeda - dan saya berpikir, ini sangat efisien dibandingkan dengan loop. Sekarang saya membutuhkan solusi Anda dan butuh satu jam mencari untuk menemukannya lagi! Terima kasih!
Michael
4
Selain itu, jika 'urutan' array (yaitu, array ('nama', 'dob', 'alamat')) memiliki lebih banyak kunci daripada array untuk mengurutkan, maka array_intersect tambahan dari array diurutkan yang dihasilkan dengan array asli akan terputus kunci liar yang ditambahkan di array_merge.
jadi
105

Ini dia:

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;
}
Eran Galperin
sumber
12
Jadi, Anda dapat bergabung dengan 2 array dengan tanda +? Saya tidak pernah tahu itu, saya telah menggunakan array_merge()!
alex
3
Apakah ini lebih baik daripada menggunakan usort()atau uasort()?
Grantwparks
5
Anda harus memasukkan breakpernyataan setelah nilai ditemukan.
Adel
4
@ alex Berhati-hatilah saat Anda mengganti array_merge()dengan +operator array . Ini bergabung dengan kunci (juga untuk kunci numerik) dan dari kiri ke kanan , sementara array_mergepenggabungan dari kanan ke kiri dan tidak pernah menimpa kunci numerik. Misal [0,1,2]+[0,5,6,7] = [0,1,2,7]sementara array_merge([0,1,2],[0,5,6,7]) = [0,1,2,0,5,6,7]dan ['a' => 5] + ['a' => 7] = ['a' => 5]tapi array_merge(['a' => 5], ['a' => 7]) = ['a' => 7].
Flu
Apakah aman menggunakan +tanda?
crmpicco
47

Bagaimana dengan solusi ini

$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));
});
Peter de Groot
sumber
1
Yang ini membutuhkan lebih banyak upvotes, yang lain tidak berfungsi / tidak berfungsi dengan baik saat ini berjalan baik dalam kasus saya.
Ng Sek Long
Ini sangat tidak efisien. Untuk setiap perbandingan, dua pencarian linear dalam array dilakukan. Jika kita menganggap kompleksitas waktu dari uksort () O(n * log n), maka algoritma ini berjalan O(n^2 * log(n)).
TheOperator
36

Cara lain untuk 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);

Hasil:

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

Berfungsi baik dengan string dan tombol angka.

ekuser
sumber
2
+ Sementara keduanya bekerja, saya menemukan array_replace()untuk menyampaikan maksud lebih baik daripada array_merge().
Jason McCreary
1
array_replacejuga meninggalkan tipe variabel utuh. Jika salah satu nilai dalam array Anda akan (string) '1'dan Anda akan menggunakan +operator, nilainya akan berubah menjadi(int) 1
halfpastfour.am
1
Ini juga berfungsi pada tombol angka ( array_merge()hanya akan menambahkannya?). Logikanya dijelaskan dengan sangat baik di sini . Pertama , array_flip()ubah nilai array pesanan $ ke kunci. Kedua , array_replace()mengganti nilai-nilai array pertama dengan nilai-nilai yang memiliki kunci yang sama di array kedua. Jika Anda perlu mengurutkan array berdasarkan kunci dari yang lain, Anda bahkan tidak perlu menggunakannya 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;
}
OIS
sumber
14

Ambil satu larik sebagai pesanan Anda:

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

Anda dapat mengurutkan array lain berdasarkan nilai menggunakan array_intersectDocuments :

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

Atau dalam kasus Anda, untuk mengurutkan berdasarkan kunci, gunakan array_intersect_keyDocuments :

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

Kedua fungsi akan menjaga urutan parameter pertama dan hanya akan mengembalikan nilai (atau kunci) dari array kedua.

Jadi untuk dua kasus standar ini Anda tidak perlu menulis fungsi sendiri untuk melakukan penyortiran / pengaturan ulang.

hakre
sumber
Perpotongan akan menyingkirkan entri yang dia tidak tahu sebelumnya.
DanMan
1
Ini tidak benar untuk mengurutkan berdasarkan kunci. array_intersect_key hanya akan mengembalikan nilai dari array1, bukan array2
seram
Setuju dengan pavsid - contoh array_intersect_key salah - mengembalikan nilai dari array pertama, bukan yang kedua.
Jonathan Aquino
10

Saya menggunakan solusi Darkwaltz4 tetapi digunakan array_fill_keyssebagai pengganti array_flip, untuk mengisinya dengan NULLjika kunci tidak disetel $array.

$properOrderedArray = array_replace(array_fill_keys($keys, null), $array);
Baptiste Bernard
sumber
5

Tanpa sihir ...

$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;
}
Jenovai Matyas
sumber
1
Ini berfungsi dengan baik terima kasih, cukup perbarui $datasetuntuk mencocokkan nama parameter
kursus
3

JIKA Anda memiliki array dalam array Anda, Anda harus menyesuaikan fungsi dengan Eran sedikit ...

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;
}
Boombastik
sumber
2

Fungsi ini mengembalikan sub dan array yang diurutkan berdasarkan parameter $ kunci kedua

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

Contoh:

$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];
Doglas
sumber
1

PHP memiliki fungsi untuk membantu Anda dalam hal ini:

$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 melakukan semua pekerjaan untuk Anda dan array_search menyediakan kunci. array_search () mengembalikan false ketika tidak dapat menemukan kecocokan sehingga item yang tidak ada dalam susunan sortir secara alami pindah ke bagian bawah array.

Catatan: uasort () akan memesan array tanpa memengaruhi hubungan nilai kunci =>.

danielcraigie
sumber
1
  • urutkan sesuai permintaan
  • simpan untuk int-kunci (karena array_replace)
  • jangan kembalikan kunci tidak ada di inputArray
  • (opsional) filter kunci tidak ada di keyList yang diberikan

Kode:

 /**
 * 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;
}
Gandum
sumber
1

Saran pertama

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

Saran kedua

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

Saya ingin menunjukkan bahwa kedua saran ini luar biasa. Namun, mereka adalah apel dan jeruk. Perbedaan? Satu ramah non-asosiatif dan yang lain ramah asosiatif. Jika Anda menggunakan 2 array asosiatif penuh maka array menggabungkan / membalik sebenarnya akan menggabungkan dan menimpa array asosiatif lainnya. Dalam kasus saya itu bukan hasil yang saya cari. Saya menggunakan file settings.ini untuk membuat susunan urutan pengurutan. Array data yang saya sortir tidak perlu ditulis oleh rekan sortasi asosiatif saya. Dengan demikian array gabungan akan menghancurkan array data saya. Keduanya adalah metode yang hebat, keduanya harus diarsipkan di kotak alat pengembang apa pun. Berdasarkan kebutuhan Anda, Anda mungkin benar-benar membutuhkan kedua konsep di arsip Anda.

pengguna1653711
sumber
1

Saya mengadopsi jawaban dari @ Darkwaltz4 untuk singkatnya dan ingin berbagi bagaimana saya mengadaptasi solusi untuk situasi di mana array dapat berisi kunci yang berbeda untuk setiap iterasi seperti:

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

dan mempertahankan "kunci utama" seperti:

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

array_merge akan mengeksekusi penggabungan dalam iterasi Array [1] berdasarkan $ master_key dan menghasilkan ['some_key'] = '', nilai kosong, untuk iterasi itu. Karenanya, array_intersect_key digunakan untuk memodifikasi $ master_key di setiap iterasi seperti:

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

Sedikit terlambat, tetapi saya tidak dapat menemukan cara saya mengimplementasikannya, versi ini perlu ditutup, php> = 5.3, tetapi dapat diubah tidak menjadi:

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

Tentu saja 'dontSortMe' perlu disortir, dan dapat muncul pertama kali dalam contoh

DJules
sumber