Sắp xếp một mảng theo các khóa dựa trên một mảng khác?


153

PHP có thể làm điều gì đó như thế này không? Làm thế nào bạn sẽ đi về viết một chức năng? Đây là một ví dụ. Thứ tự là điều quan trọng nhất.

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

Và tôi muốn làm một cái gì đó như

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

Bởi vì cuối cùng, tôi sử dụng một foreach () và chúng không theo đúng thứ tự (vì tôi nối các giá trị vào một chuỗi cần theo đúng thứ tự và tôi không biết trước tất cả các khóa mảng / các giá trị).

Tôi đã xem qua các hàm mảng bên trong của PHP nhưng có vẻ như bạn chỉ có thể sắp xếp theo thứ tự chữ cái hoặc số.

Câu trả lời:


347

Chỉ cần sử dụng array_mergehoặc array_replace. Array_mergehoạt động bằng cách bắt đầu với mảng bạn cung cấp cho nó (theo đúng thứ tự) và ghi đè / thêm các khóa với dữ liệu từ mảng thực tế của bạn:

$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 - Tôi đang trả lời câu hỏi 'cũ' này, bởi vì tôi nghĩ rằng tất cả các vòng lặp được đưa ra như câu trả lời trước đó là quá mức cần thiết.


31
Nó hoạt động độc đáo nếu bạn có các phím chuỗi nhưng không phải cho số. Tài liệu PHP: "Nếu các mảng đầu vào có cùng các khóa chuỗi, thì giá trị sau cho khóa đó sẽ ghi đè lên trước đó. Tuy nhiên, nếu các mảng chứa các khóa số, giá trị sau sẽ không ghi đè giá trị ban đầu, nhưng sẽ nối thêm. "
bolbol

7
Đẹp, nhưng nếu các khóa không tồn tại trong các giá trị thì sao? Tôi cần cái này, nhưng chỉ khi có bất kỳ chìa khóa nào tồn tại ... Có lẽ cần một lời tiên tri về nó sau đó ...
Solomon Closson

5
đối với trường hợp của tôi, đó là mảng numplace thay vì Array_merge. mảng_merge kết hợp cả hai giá trị thay vì thay thế mảng thứ hai vào các khóa được sắp xếp.
neofreko

3
Tôi tình cờ tìm thấy giải pháp của bạn vài năm trước trong khi tìm kiếm thứ gì đó khác biệt - và tôi tự nghĩ, điều này cực kỳ hiệu quả so với các vòng lặp. Bây giờ tôi có nhu cầu về giải pháp của bạn và tôi đã mất một giờ tìm kiếm để tìm lại nó! Cảm ơn!
Michael

4
Ngoài ra, nếu mảng 'order' (nghĩa là mảng ('name', 'dob', 'address')) có nhiều khóa hơn mảng cần sắp xếp, thì mảng_intersect bổ sung của mảng được sắp xếp kết quả với mảng ban đầu sẽ bị cắt các khóa đi lạc đã được thêm vào tại Array_merge.
bbe

105

Bạn đi đây

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
Vì vậy, bạn có thể tham gia 2 mảng với dấu +? Tôi chưa bao giờ biết rằng, tôi đã sử dụng array_merge()!
alex

3
Điều này tốt hơn so với sử dụng usort()hay uasort()?
Grantwparks

5
Bạn nên chèn một breakcâu lệnh khi giá trị được tìm thấy.
Adel

4
@alex Hãy thật cẩn thận khi bạn thay thế array_merge()bằng +toán tử mảng . Nó hợp nhất theo khóa (cũng cho các phím số) và từ trái sang phải , trong khi array_mergehợp nhất từ phải sang trái và không bao giờ ghi đè các phím số. Ví dụ [0,1,2]+[0,5,6,7] = [0,1,2,7]trong khi array_merge([0,1,2],[0,5,6,7]) = [0,1,2,0,5,6,7]['a' => 5] + ['a' => 7] = ['a' => 5]nhưng array_merge(['a' => 5], ['a' => 7]) = ['a' => 7].
cúm

Có an toàn để sử dụng các +dấu hiệu?
crmpicco

47

Giải pháp này thế nào

$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
Cái này cần nhiều upvote hơn, cái khác không hoạt động / không hoạt động tốt trong khi cái này chạy tốt trong trường hợp của tôi.
Ng Sek Long

Điều này không hiệu quả lắm. Đối với mỗi so sánh, hai tìm kiếm tuyến tính trong mảng được thực hiện. Nếu chúng ta giả sử độ phức tạp thời gian của uksort () O(n * log n), thì thuật toán này sẽ chạy trong O(n^2 * log(n)).
TheOperator

36

Một cách khác cho 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);

Kết quả:

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

Hoạt động tốt với các chuỗi chuỗi và số.


2
+ Trong khi cả hai đều làm việc, tôi thấy array_replace()chuyển tiếp ý định tốt hơn array_merge().
Jason McCreary

1
array_replacecũng để nguyên loại biến. Nếu một trong các giá trị trong mảng của bạn đã có (string) '1'và bạn đã sử dụng +toán tử, giá trị đó sẽ được chuyển thành(int) 1
Halfpastfour.am

1
Điều này cũng hoạt động trên các phím số ( array_merge()sẽ chỉ thêm chúng?). Logic được giải thích rất tốt ở đây . Đầu tiên , array_flip()thay đổi giá trị của mảng $ order thành khóa. Thứ hai , array_replace()thay thế các giá trị của mảng thứ nhất bằng các giá trị có cùng khóa trong mảng thứ hai. Nếu bạn cần sắp xếp một mảng theo các khóa từ một khóa khác, bạn thậm chí không phải sử dụng 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

Lấy một mảng theo thứ tự của bạn:

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

Bạn có thể sắp xếp một mảng khác dựa trên các giá trị bằng array_intersectDocs :

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

Hoặc trong trường hợp của bạn, để sắp xếp theo các phím, hãy sử dụng array_intersect_keyTài liệu :

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

Cả hai hàm sẽ giữ thứ tự của tham số đầu tiên và sẽ chỉ trả về các giá trị (hoặc khóa) từ mảng thứ hai.

Vì vậy, đối với hai trường hợp tiêu chuẩn này, bạn không cần phải tự viết một hàm để thực hiện sắp xếp / sắp xếp lại.


Giao lộ sẽ thoát khỏi những mục mà anh ta không biết trước.
Danman

1
Điều này là không chính xác để sắp xếp theo các phím. mảng_intersect_key sẽ chỉ trả về các giá trị từ mảng1, không phải mảng2
ma quái

Đồng ý với pavsid - ví dụ Array_intersect_key không chính xác - nó trả về các giá trị từ mảng đầu tiên, không phải thứ hai.
Jonathan Aquino

10

Tôi đã sử dụng giải pháp của Darkwaltz4 nhưng được sử dụng array_fill_keysthay vì array_flip, để điền vào NULLnếu khóa không được đặt $array.

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

5

Không có phép thuật ...

$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
Điều này hoạt động tốt cảm ơn, chỉ cần cập nhật $datasetđể khớp với tên tham số
kursus

3

NẾU bạn có mảng trong mảng của mình, bạn sẽ phải điều chỉnh chức năng bằng cách Eran một chút ...

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

Hàm này trả về một mảng con và được sắp xếp dựa trên tham số thứ hai $ key

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

Thí dụ:

$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 có các chức năng để giúp bạn với điều này:

$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 thực hiện tất cả công việc cho bạn và mảng_search cung cấp các khóa. mảng_search () trả về false khi không thể tìm thấy kết quả khớp để các mục không nằm trong mảng sắp xếp tự nhiên di chuyển xuống dưới cùng của mảng.

Lưu ý: uasort () sẽ sắp xếp mảng mà không ảnh hưởng đến các mối quan hệ khóa => giá trị.


1
  • sắp xếp theo yêu cầu
  • lưu cho các khóa int (vì mảng numplace)
  • không trả về khóa không tồn tại trong inputArray
  • (tùy chọn) các khóa bộ lọc không tồn tại trong keyList đã cho

Mã số:

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

Gợi ý đầu tiên

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

Gợi ý thứ hai

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

Tôi muốn chỉ ra rằng cả hai gợi ý này đều tuyệt vời. Tuy nhiên, chúng là táo và cam. Sự khác biệt? Một là thân thiện không liên kết và một là thân thiện kết hợp. Nếu bạn đang sử dụng 2 mảng kết hợp hoàn toàn thì mảng / flip mảng sẽ thực sự hợp nhất và ghi đè lên mảng kết hợp khác. Trong trường hợp của tôi đó không phải là kết quả mà tôi đang tìm kiếm. Tôi đã sử dụng tệp settings.ini để tạo mảng thứ tự sắp xếp của mình. Mảng dữ liệu tôi đang sắp xếp không cần phải viết lên bởi đối tác sắp xếp kết hợp của tôi. Do đó, hợp nhất mảng sẽ phá hủy mảng dữ liệu của tôi. Cả hai đều là phương thức tuyệt vời, cả hai đều cần được lưu trữ trong bất kỳ hộp công cụ dành cho nhà phát triển nào. Dựa trên nhu cầu của bạn, bạn có thể thấy bạn thực sự cần cả hai khái niệm trong kho lưu trữ của bạn.


1

Tôi đã chấp nhận câu trả lời từ @ Darkwaltz4 vì sự ngắn gọn của nó và muốn chia sẻ cách tôi điều chỉnh giải pháp cho các tình huống trong đó mảng có thể chứa các khóa khác nhau cho mỗi lần lặp như vậy:

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

và duy trì "khóa chính" như vậy:

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

mảng_merge sẽ thực hiện hợp nhất trong phép lặp Array [1] dựa trên $ master_key và tạo ra ['some_key'] = '', một giá trị trống, cho lần lặp đó. Do đó, Array_intersect_key đã được sử dụng để sửa đổi $ master_key trong mỗi lần lặp như vậy:

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

0

Hơi muộn một chút, nhưng tôi không thể tìm thấy cách tôi triển khai nó, phiên bản này cần đóng, php> = 5.3, nhưng có thể được thay đổi không thành:

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

Tất nhiên, 'dontSortMe' cần được sắp xếp và có thể xuất hiện đầu tiên trong ví dụ

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.