จัดเรียง Array ตามคีย์ตาม Array อื่นหรือไม่


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

ป.ล. - ฉันกำลังตอบคำถาม 'ค้าง' นี้เพราะฉันคิดว่าลูปทั้งหมดที่ได้รับเนื่องจากคำตอบก่อนหน้านั้นเกินความจริง


31
มันทำงานได้ดีถ้าคุณมีคีย์สตริง แต่ไม่ใช่สำหรับตัวเลข PHP Docs: "หากอาร์เรย์อินพุตมีคีย์สตริงเหมือนกันดังนั้นค่าในภายหลังสำหรับคีย์นั้นจะเขียนทับคีย์ก่อนหน้านี้อย่างไรก็ตามหากอาร์เรย์มีคีย์ตัวเลขค่าในภายหลังจะไม่เขียนทับค่าเดิม แต่จะเป็น ผนวก."
bolbol

7
ดีมาก แต่ถ้าคีย์ไม่มีอยู่ในค่าจะเป็นอย่างไร ฉันต้องการ แต่ถ้าใด ๆ ของกุญแจที่มีอยู่ ... อาจจะต้อง foreach กับมันแล้ว ...
โซโลมอน Closson

5
สำหรับกรณีของฉันมันคือ array_replace แทนที่จะเป็น array_merge array_merge รวมทั้งสองค่าแทนการแทนที่อาเรย์ที่สองลงในคีย์ที่ได้รับคำสั่ง
neofreko

3
ฉันเจอปัญหาของคุณเมื่อสองสามปีก่อนในขณะที่ค้นหาสิ่งที่แตกต่าง - และฉันคิดกับตัวเองว่ามันมีประสิทธิภาพมากเมื่อเทียบกับลูป ตอนนี้ฉันต้องการโซลูชันของคุณและใช้เวลาหนึ่งชั่วโมงในการค้นหาเพื่อค้นหามันอีกครั้ง! ขอบคุณ!
Michael

4
นอกจากนี้หากอาร์เรย์ 'คำสั่ง' (เช่นอาร์เรย์ ('ชื่อ', 'dob', 'ที่อยู่')) มีคีย์มากกว่าอาร์เรย์ที่จะเรียงลำดับแล้ว 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()!
alex

3
มันดีกว่าใช้usort()หรือuasort()เปล่า?
grantwparks

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]
ไข้หวัดใหญ่

การใช้+สัญลักษณ์ปลอดภัยหรือไม่?
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

มันไม่ได้มีประสิทธิภาพมาก ทุกการเปรียบเทียบจะทำการค้นหาเชิงเส้นสองครั้งในอาร์เรย์ ถ้าเราคิดซับซ้อนเวลาของการ 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

1
array_replaceยังปล่อยให้ตัวแปรชนิดไม่เปลี่ยนแปลง หากหนึ่งในค่าในอาร์เรย์ของคุณน่าจะเป็น(string) '1'และคุณได้ใช้+โอเปอเรเตอร์แล้วค่าจะกลายเป็น(int) 1
halfpastfour.am

1
สิ่งนี้ใช้ได้กับปุ่มตัวเลขarray_merge()ด้วย ตรรกะจะมีการอธิบายอย่างดีที่นี่ ก่อนอื่นให้array_flip()เปลี่ยนค่าของ $ order array เป็นคีย์ ประการที่สอง , array_replace()แทนค่าของอาร์เรย์แรกที่มีค่ามีคีย์เดียวกันในแถวที่สอง 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

รับหนึ่งอาร์เรย์เป็นคำสั่งของคุณ:

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

คุณสามารถจัดเรียงอาร์เรย์อื่นตามค่าโดยใช้array_intersectเอกสาร :

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

ทั้งสองฟังก์ชั่นจะรักษาลำดับของพารามิเตอร์แรกและจะคืนค่า (หรือคีย์) จากอาเรย์ที่สองเท่านั้น

ดังนั้นสำหรับกรณีมาตรฐานสองกรณีนี้คุณไม่จำเป็นต้องเขียนฟังก์ชันด้วยตัวเองเพื่อทำการเรียงลำดับ / จัดเรียงใหม่


จุดตัดจะกำจัดรายการเหล่านั้นที่เขาไม่ทราบล่วงหน้า
DanMan

1
สิ่งนี้ไม่ถูกต้องสำหรับการเรียงลำดับโดยใช้คีย์ array_intersect_key จะคืนค่าจาก array1 ไม่ใช่ array2
เหมือนผี

เห็นด้วยกับ pavsid - ตัวอย่าง array_intersect_key ไม่ถูกต้อง - ส่งคืนค่าจากอาร์เรย์แรกไม่ใช่วินาที
Jonathan Aquino


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เพื่อจับคู่ชื่อพารามิเตอร์
kursus

3

หากคุณมีอาเรย์ในอาเรย์ของคุณคุณจะต้องปรับฟังก์ชั่นโดย Eran เล็กน้อย ...

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

ฟังก์ชันนี้คืนค่าอาร์เรย์ย่อยและเรียงลำดับตามพารามิเตอร์ที่สอง $ 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-keys (เพราะ 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;
}

ข้อเสนอแนะที่สอง

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

ฉันต้องการชี้ให้เห็นว่าคำแนะนำทั้งสองนี้ยอดเยี่ยมมาก อย่างไรก็ตามพวกเขาเป็นแอปเปิ้ลและส้ม ความแตกต่าง? หนึ่งคือไม่เป็นมิตรเชื่อมโยงและอื่น ๆ เป็นกันเองเชื่อมโยง หากคุณใช้ 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 จะทำการดำเนินการผสานใน Array [1] ซ้ำตาม $ master_key และสร้าง ['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.