다른 배열을 기반으로 키로 배열을 정렬 하시겠습니까?


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_replace. Array_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_merge 대신 array_replace입니다. array_merge는 두 번째 배열을 순서가 지정된 키로 바꾸는 대신 두 값을 결합합니다.
neofreko

3
몇 년 전에 다른 것을 검색하는 동안 솔루션을 우연히 발견했으며 루프에 비해 매우 효율적이라고 생각했습니다. 이제 귀하의 솔루션이 필요하며 다시 찾는 데 한 시간이 걸렸습니다! 감사!
Michael

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()!
alex

3
이 사용하는 것보다 더 나은가요 usort()uasort()?
grantwparks

5
break값을 찾으면 명령문을 삽입해야합니다 .
Adel

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()키에 $ 순서 배열의 값을 변경합니다. 둘째로 , array_replace()값이 제 2 어레이의 동일한 키를 갖는 제 배열의 값을 대체한다. 다른 키의 키에 따라 배열을 정렬 해야하는 경우조차 사용할 필요가 없습니다 array_flip.
aexl December

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_intersectDocs를 사용하여 값을 기반으로 다른 배열을 정렬 할 수 있습니다 .

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

또는 귀하의 경우 키별로 정렬하려면 array_intersect_keyDocs를 사용하십시오 .

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

두 함수 모두 첫 번째 매개 변수의 순서를 유지하고 두 번째 배열의 값 (또는 키) 만 반환합니다.

따라서이 두 표준 사례의 경우 정렬 / 재정렬을 수행하기 위해 직접 함수를 작성할 필요가 없습니다.


교차점은 미리 알지 못하는 항목을 제거합니다.
DanMan

1
키를 기준으로 정렬하는 것은 올바르지 않습니다. array_intersect_key는 array2가 아닌 array1의 값만 반환합니다
으스스한

pavsid와 동의-array_intersect_key 예제가 잘못되었습니다-두 번째 배열이 아닌 첫 번째 배열의 값을 반환합니다.
Jonathan Aquino

10

Darkwaltz4의 솔루션을 사용했지만 키가 설정되어 있지 않은 경우 채우기 위해 array_fill_keys대신 사용 했습니다 .array_flipNULL$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일치 매개 변수 이름
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 키를 저장하십시오 (배열 _ 대체로 인해)
  • 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는 $ 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.