Bir Diziyi başka bir Diziye göre anahtarlara göre sıralamak?


153

PHP'de böyle bir şey yapmak mümkün mü? Bir fonksiyon yazmaya nasıl devam edersiniz? İşte bir örnek. Sıra en önemli şeydir.

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

Ve böyle bir şey yapmak istiyorum

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

Çünkü sonunda bir foreach () kullanın ve onlar doğru sırada değiller (çünkü ben doğru sırada olması gereken bir dizeye değerleri eklemek ve önceden tüm dizi anahtarları bilmiyorum / değerleri).

Ben PHP'nin dahili dizi fonksiyonları üzerinden baktım ama sadece alfabetik veya sayısal olarak sıralayabilirsiniz görünüyor.

Yanıtlar:


347

Sadece array_mergeveyaarray_replace . Array_mergeverdiğiniz diziden başlayarak (doğru sırada) ve gerçek dizinizdeki verilerle anahtarların üzerine yazarak / ekleyerek çalışır:

$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 - Bu 'bayat' sorusunu cevaplıyorum, çünkü önceki cevaplar olarak verilen tüm döngülerin aşırı olduğunu düşünüyorum.


31
Dize anahtarlarınız varsa güzel çalışır, ancak sayısal tuşlar için uygun değildir. PHP Docs: "Giriş dizileri aynı dize anahtarlarına sahipse, o anahtarın sonraki değeri öncekinin üzerine yazılır. Ancak, diziler sayısal anahtarlar içeriyorsa, sonraki değer orijinal değerin üzerine yazılmaz, ancak eklenir."
bolbol

7
Güzel, ama ya anahtarlarda değer yoksa? Buna ihtiyacım var, ama sadece anahtarlardan herhangi biri varsa ... Muhtemelen üzerinde bir
öngörü

5
benim durumum için array_merge yerine array_replace. array_merge, ikinci diziyi sıralı tuşlarla değiştirmek yerine her iki değeri birleştirir.
neofreko

3
Birkaç yıl önce farklı bir şey ararken çözümünüze rastladım - ve kendi kendime düşündüm, bu döngülere kıyasla son derece verimli. Şimdi çözümünüze ihtiyacım var ve tekrar bulmak için bir saat sürdü! Teşekkürler!
Michael

4
Buna ek olarak, 'order' dizisi (yani, dizi ('name', 'dob', 'address')) sıralanacak diziden daha fazla anahtara sahipse, sonuçta orijinal dizinin bulunduğu sıralanmış dizinin ek array_intersect'i kesilir array_merge öğesine eklenen sokak anahtarları.
bbe

105

İşte böyle:

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
+ İşaretiyle 2 diziye katılabilir misiniz? Bunu hiç bilmiyordum, kullanıyorum array_merge()!
alex

3
Bu, usort()veya kullanmaktan daha mı iyi uasort()?
grantwparks

5
breakDeğer bulunduğunda bir ifade eklemeniz gerekir .
Adel

4
@alex array_merge()Dizi +operatörü ile değiştirirken çok dikkatli olun . O (aynı zamanda sayısal tuşlar için) ve gelen anahtar ile birleştirir soldan sağa iken, array_mergegelen birleştirmeleri sağa sola ve asla sayısal tuşlar üzerine yazar. Örneğin [0,1,2]+[0,5,6,7] = [0,1,2,7]ederken array_merge([0,1,2],[0,5,6,7]) = [0,1,2,0,5,6,7]ve ['a' => 5] + ['a' => 7] = ['a' => 5]ancak array_merge(['a' => 5], ['a' => 7]) = ['a' => 7].
grip

+İşareti kullanmak güvenli mi?
crmpicco

47

Bu çözüme ne dersiniz?

$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
Bu bir daha fazla oy gerekir, diğer işe yaramadı / bu benim durumumda iyi çalışırken iyi çalışmaz.
Ng Sek Long

Bu çok verimli değil. Her karşılaştırma için dizideki iki doğrusal arama gerçekleştirilir. Uksort () 'un zaman karmaşıklığını varsayarsak, O(n * log n)bu algoritma devreye girer O(n^2 * log(n)).
TheOperator

36

PHP için başka bir yol> = 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);

Sonuç:

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

Dize ve sayısal tuşlarla iyi çalışır.


2
+ İkisi de çalışırken, array_replace()niyeti daha iyi buldum array_merge().
Jason McCreary

1
array_replaceayrıca değişken türünü olduğu gibi bırakır. Sizin dizideki değerlerden biri olurdu varsa (string) '1've kullanmış olurdu +operatörü, değer dönüştü olurdu(int) 1
halfpastfour.am

1
Bu aynı zamanda sayısal tuşlar üzerinde de çalışır ( array_merge()sadece ekler misiniz?). Mantık çok iyi açıklanmıştır burada . İlk olarak , array_flip()$ order dizisinin değerlerini key olarak değiştirir. İkinci olarak , array_replace()ilk dizinin değerlerini ikinci dizide aynı anahtarlara sahip değerlerle değiştirir. Bir diziyi bir başkasının tuşlarına göre sıralamanız gerekiyorsa, kullanmanız bile gerekmez 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

Siparişiniz olarak bir dizi alın:

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

array_intersectDokümanlar'ı kullanarak başka bir diziyi değerlere göre sıralayabilirsiniz :

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

Veya durumunuzda, tuşlara göre sıralamak için Google array_intersect_keyDokümanlar'ı kullanın :

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

Her iki işlev de ilk parametrenin sırasını korur ve yalnızca ikinci diziden değerleri (veya anahtarları) döndürür.

Bu nedenle bu iki standart durumda, sıralama / yeniden düzenlemeyi gerçekleştirmek için kendi başınıza bir işlev yazmanıza gerek yoktur.


Kesişme, önceden bilmediği girişlerden kurtulacaktır.
DanMan

1
Bu, tuşlara göre sıralama için yanlıştır. array_intersect_key, array2 yerine yalnızca array1'deki değerleri döndürür
spooky

Pavsid ile aynı fikirde - array_intersect_key örneği yanlış - ikinci diziden değil, birinci dizideki değerleri döndürür.
Jonathan Aquino

10

Darkwaltz4'ün çözümünü kullandım, ancak array_fill_keysyerine bir anahtar yerleştirilmemişse array_flipdoldurmak için kullandım .NULL$array

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

5

Büyü olmadan ...

$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
Bu güzel çalışıyor, sadece $datasetparametre adı ile eşleşecek şekilde güncelleyin
kursus

3

Dizinizde bir dizi varsa, Eran'ın fonksiyonunu biraz uyarlamanız gerekir ...

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

Bu işlev, ikinci parametre $ anahtarlarına dayalı olarak bir alt ve sıralı dizi döndürür

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

Misal:

$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 bu konuda size yardımcı olacak fonksiyonlara sahiptir:

$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 sizin için tüm işleri yapar ve dizi_search tuşları sağlar. array_search (), sıralama dizisinde bulunmayan öğelerin doğal olarak dizinin altına taşınması için bir eşleşme bulamadığında false değerini döndürür.

Not: uasort (), anahtar => değer ilişkilerini etkilemeden diziyi sıralar.


1
  • istendiği gibi sırala
  • int anahtarları için kaydet (array_replace nedeniyle)
  • dönüş anahtarları inputArray içinde mevcut değil
  • (isteğe bağlı olarak) filtre anahtarları verilen keyList'te mevcut değil

Kod:

 /**
 * 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

İlk Öneri

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

İkinci Öneri

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

Bu önerilerin her ikisinin de harika olduğunu belirtmek istedim. Ancak, bunlar elma ve portakal. Fark? Biri ilişkisel olmayan, diğeri ilişkisel dosttur. 2 tam ilişkilendirilebilir dizi kullanıyorsanız, birleştirme / çevirme dizisi aslında diğer ilişkilendirilebilir diziyi birleştirir ve üzerine yazar. Benim durumumda aradığım sonuç bu değil. Sıralama düzeni dizimi oluşturmak için bir settings.ini dosyası kullandım. Ben sıralama veri dizisi benim ilişkilendirilebilir sıralama muadili tarafından üzerine yazmak zorunda değildi. Böylece dizi birleştirme veri dizimi yok eder. Her ikisi de harika yöntemlerdir, her ikisinin de herhangi bir geliştirici araç kutusunda arşivlenmesi gerekir. İhtiyaçlarınıza bağlı olarak, arşivlerinizde her iki kavramın da gerekli olduğunu görebilirsiniz.


1

Ben kendi kısalığı için @ Darkwaltz4 gelen yanıtı kabul etti ve ben dizi gibi her yineleme için farklı anahtarlar içerebilir durumlara çözüm adapte nasıl paylaşmak istiyorum:

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

ve şu şekilde bir "ana anahtar" tuttu:

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

array_merge, $ master_key temel alınarak Array [1] yinelemesinde birleştirmeyi gerçekleştirir ve bu yineleme için boş bir değer olan ['some_key'] = '' üretir. Bu nedenle, array_intersect_key, her bir yinelemede $ master_key öğesini değiştirmek için kullanıldı:

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

0

Biraz geç, ancak uyguladığım yolu bulamadım, bu sürümün kapanması gerekiyor, php> = 5.3, ancak değiştirilemez:

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

Tabii ki 'dontSortMe' dizilmeli ve örnekte ilk görünebilir

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.