PHP에서 주어진 키의 값으로 연관 배열의 배열을 정렬하는 방법은 무엇입니까?


446

이 배열이 주어지면 :

$inventory = array(

   array("type"=>"fruit", "price"=>3.50),
   array("type"=>"milk", "price"=>2.90),
   array("type"=>"pork", "price"=>5.43),

);

$inventory가격을 기준으로의 요소 를 정렬하고 싶습니다 .

$inventory = array(

   array("type"=>"pork", "price"=>5.43),
   array("type"=>"fruit", "price"=>3.50),
   array("type"=>"milk", "price"=>2.90),

);

어떻게해야합니까?


답변:


606

당신이 맞습니다, 당신이 찾고있는 기능은 array_multisort()입니다.

다음은 설명서에서 직접 가져 와서 사례에 맞게 수정 한 예입니다.

$price = array();
foreach ($inventory as $key => $row)
{
    $price[$key] = $row['price'];
}
array_multisort($price, SORT_DESC, $inventory);

PHP 5.5.0부터 foreach 대신 array_column ()을 사용할 수 있습니다

$price = array_column($inventory, 'price');

array_multisort($price, SORT_DESC, $inventory);

5
비록 이것이 대안보다 확실히 비싸지 만.
Matt

5
더 비싼? 이상하게도 내 컴퓨터 (PHP 5.3.1-dev를 실행)에서 array_multisort ()는 작은 배열에서는 몇 퍼센트 빠르며 큰 배열 (100 개 이상의 요소)에서는 100 배 빠릅니다.
Josh Davis

3
숫자 키를 사용하기 위해 변경하지 않아도됩니다. 숫자 키와 관련된 버그 또는 이상한 동작을하는 경우 새 질문으로 게시하십시오.
Josh Davis

4
array_multisort에는 큰 문제가 있습니다. 원래 키를 유지하지 않습니다.
machineaddict

1
@machineaddict 그것은 연관 키를 유지합니다.
Matej Svajger

318

PHP 7 이상

PHP 7부터는 우주선 연산자 를 사용하여 요소를 비교 usort하는 익명 함수 를 사용 하여 간결하게 수행 할 수 있습니다 .

다음과 같이 오름차순 정렬을 수행 할 수 있습니다.

usort($inventory, function ($item1, $item2) {
    return $item1['price'] <=> $item2['price'];
});

또는 다음과 같이 내림차순으로 정렬하십시오.

usort($inventory, function ($item1, $item2) {
    return $item2['price'] <=> $item1['price'];
});

이것이 어떻게 작동하는지 이해하려면 usort(문서에서) 다음과 같이 동작 해야하는 사용자 제공 비교 기능이 필요합니다.

비교 함수는 첫 번째 인수가 각각 두 번째보다 작거나 같거나 큰 것으로 간주되는 경우 0보다 작거나 같거나 0보다 큰 정수를 반환해야합니다.

또한 참고 <=> , 우주선 연산자

두 피연산자가 모두 같으면 0을, 왼쪽이 더 크면 1을, 오른쪽이 더 크면 -1을 반환합니다.

정확히 필요한 usort것입니다. 실제로 https://wiki.php.net/rfc/combined-comparison-operator<=> 에서 언어에 추가 하기 위해 주어진 거의 모든 정당화 는

와 함께 사용할 주문 콜백 작성 usort() 보다 쉽게하기


PHP 5.3 이상

PHP 5.3에는 익명 함수가 도입되었지만 아직 우주선 연산자가 없습니다. 우리는 여전히 usort배열을 정렬 하는 데 사용할 수 있지만 조금 더 장황하고 이해하기 어렵습니다.

usort($inventory, function ($item1, $item2) {
    if ($item1['price'] == $item2['price']) return 0;
    return $item1['price'] < $item2['price'] ? -1 : 1;
});

참고 그냥 값의 차이를 반환하는 정수 값을 처리 비교기에 대한 매우 일반적인 비록 같은 것을 $item2['price'] - $item1['price'], 우리가 할 수 안전하게 그렇게이 경우이다. 이것은 질문 asker의 예에서 가격이 부동 소수점 숫자이지만 우리가 전달하는 비교 함수는 제대로 작동 usort하기 usort위해 정수를 반환 해야하기 때문입니다 .

정수가 아닌 반환 같은 플로트 같이, 비교 함수의 값을 콜백의 반환 값의 정수 내부 캐스팅 될 것이다. 따라서 0.99 및 0.1과 같은 값은 모두 0의 정수 값으로 캐스팅되어 해당 값을 동일한 값으로 비교합니다.

usortPHP 5.x에서 사용할 때 명심해야 할 중요한 함정입니다 ! 이 답변의 원래 버전은이 실수를했지만 심각한 버그를 알리지 않고 수천 번의 견해에 대해 10 개의 공감대를 얻었습니다. 저 비교기 기능을 망칠 수있는 것처럼 용이성은 함께 lackwits 정확하게 쉽게 사용할 수있는 우주선 연산자 PHP 7 언어에 첨가하는 이유는.


8
죄송하지만이 방법은 연관 배열에서 문자열 키를 삭제합니다. 대신 "uasort"기능을 사용해야합니다.
Matteo-SoftNet

8
@DotMat Interesting-에 대해 몰랐습니다 uasort. 그러나 문서를 본 후에도이 대답은 여전히 ​​옳 습니다 . OP의 예에서 정렬 할 배열에는 문자열 인덱스가 아닌 순차적 숫자 인덱스가 있으므로 usort더 적합합니다. 사용 uasort순차적 인덱싱 배열하는 단계에서 본 제 소자되도록 그 수치 인덱스에 따라 정렬되지 않은 배열 정렬 될 것이다 foreach루프가없는 $your_array[0]것이 문제가 될 가능성이있다.
Mark Amery 12

100

다른 사람들이의 사용을 올바르게 제안했지만 array_multisort()어떤 이유로 든 array_column()솔루션 의 존재를 인정하는 답변이 없어 솔루션을 크게 단순화 할 수 있습니다. 그래서 내 제안은 다음과 같습니다.

array_multisort(array_column($inventory, 'price'), SORT_DESC, $inventory);

1
어떤 이유로 나는 소문자 / 대문자를 가진 문자열로 작동시키지 못했습니다. SORT_FLAG_CASE를 사용하더라도. 다음은 나를 위해 문자열 비교에 효과적이었습니다. array_multisort (array_map (strtolower, array_column ($ ipr_projects, 'Name')), SORT_ASC, $ ipr_projects);
Pabamato

8
이것은 가장 우아한 답변입니다. 훨씬 높은 등급이어야합니다!
Armin Hierstetter

3
가장 짧고 쉬운 것, 내 의견으로는 받아 들여진 것
StudioX

1
여기 좋은 물건. 나를 위해 완벽하게 일했습니다!
Funk Doc

매력처럼 일했습니다
Leif_Lundberg

42

배열 요소는 문자열 키가있는 배열 자체이므로 사용자 지정 비교 함수를 정의하는 것이 가장 좋습니다. 매우 빠르고 쉽습니다. 이 시도:

function invenDescSort($item1,$item2)
{
    if ($item1['price'] == $item2['price']) return 0;
    return ($item1['price'] < $item2['price']) ? 1 : -1;
}
usort($inventory,'invenDescSort');
print_r($inventory);

다음을 생성합니다.

Array
(
    [0] => Array
        (
            [type] => pork
            [price] => 5.43
        )

    [1] => Array
        (
            [type] => fruit
            [price] => 3.5
        )

    [2] => Array
        (
            [type] => milk
            [price] => 2.9
        )

)

4
여기에 다른 의견들 (어 소트 및 인라인 익명 함수)과 결합하여 다음과 같은 단일 라이너를 얻을 수 있습니다.uasort( $inventory, function ($a, $b) { if ( $a==$b ) return 0; else return ($a > $b) ? -1 : 1; });
Alan Porter

@AlanPorter usortuasort순차적 인 숫자 키로 배열을 정렬하는 것보다 더 적합 합니다. 첫 번째 요소가 색인에 1있고 두 번째 요소가 색인에있는 배열로 끝나는 0것은 이상한 행동이며 PHP 배열의 세부 사항에 익숙하지 않은 사람들에게는 확실한 함정입니다. usort직관적으로 기대할 수있는 결과를 제공합니다.
Mark Amery 23

25

나는 이것으로 끝났다.

function sort_array_of_array(&$array, $subfield)
{
    $sortarray = array();
    foreach ($array as $key => $row)
    {
        $sortarray[$key] = $row[$subfield];
    }

    array_multisort($sortarray, SORT_ASC, $array);
}

배열과 두 번째 수준 배열의 필드 이름을 전달하여 함수를 호출하십시오. 처럼:

sort_array_of_array($inventory, 'price');

1
하아! 난 정확히 똑같은 것을 만들고 게시하려고했지만 당신의 것을 보았습니다 ... upvoted.
Rob Evans

1
Josh Davis가 몇 년 전에 게시 한 것과 동일한 솔루션이기 때문에 다운 보팅.
Mark Amery

동의하지 않습니다 ... 나는 그것이 다른 해결책이라고 말하지 않았습니다. 방금이 해결책으로 끝내고 완전한 작동 기능을 제공한다고 말했습니다.
Danielzt

1
@MarkAmery 나는 함수에 포함 된 답변을 선호합니다. 복사 파서 트가 함수를 사용하고 더 적은 스파게티 코드를 작성하도록 장려합니다.
Goose

19

usort익명 기능과 함께 사용할 수 있습니다 . 예 :

usort($inventory, function ($a, $b) { return strnatcmp($a['price'], $b['price']); });

버전 PHP 5> = 5.5.0, PHP 7은 저와 같은 분들을 위해이 기능이 실제로 사용되기를 원했습니다.
Matt P

1
놀라운 것으로는 strnatcmp, 문자열을 비교하는 의미, 여기 잘 작동 보인다. 분명히 그것이 구현하는 "자연 순서"는 어휘보다는 숫자로 문자열을 정렬하는 것을 포함합니다.
Mark Amery 2016 년

10
$inventory = 
    array(array("type"=>"fruit", "price"=>3.50),
          array("type"=>"milk", "price"=>2.90),
          array("type"=>"pork", "price"=>5.43),
          );

function pricesort($a, $b) {
  $a = $a['price'];
  $b = $b['price'];
  if ($a == $b)
    return 0;
  return ($a > $b) ? -1 : 1;
}

usort($inventory, "pricesort");
// uksort($inventory, "pricesort");

print("first: ".$inventory[0]['type']."\n\n");
// for usort(): prints milk (item with lowest price)
// for uksort(): prints fruit (item with key 0 in the original $inventory)

// foreach prints the same for usort and uksort.
foreach($inventory as $i){
  print($i['type'].": ".$i['price']."\n");
}

출력 :

first: pork

pork: 5.43
fruit: 3.5
milk: 2.9

6

From PHP에서 주어진 키의 값을 기준으로 연관 배열의 배열을 정렬하십시오 .

uasort ( http://php.net/uasort )를 사용하면 자신이 정의한 함수로 배열을 정렬 할 수 있습니다. 귀하의 경우에는 간단합니다.

$array = array(
  array('price'=>'1000.50','product'=>'test1'),
  array('price'=>'8800.50','product'=>'test2'),
  array('price'=>'200.0','product'=>'test3')
);

function cmp($a, $b) {
  return $a['price'] > $b['price'];
}

uasort($array, "cmp");

1
이 답변은 코드에 대한 설명을 제공하지 않기 때문에 품질이 낮은 검토 대기열에 나타납니다. 이 코드가 질문에 대한 답변이면 코드를 설명하는 텍스트를 추가하여 추가하십시오. 이렇게하면 더 많은 투표를 할 가능성이 높아지고 질문자가 새로운 것을 배우도록 도울 수 있습니다.
lmo

1
흠. 이것이 가장 좋은 답변입니다.
commonpike

1
-1; cmp여기 의 기능이 잘못되었습니다. 반환하기로했다 "이하,보다 정수에 동일, 또는 초보다 같거나보다 큰 제로는 첫 번째 인수는 덜보다 각각 것으로 간주되는 경우" 대신 반환 true또는 false. 그럼에도 불구하고 놀랍게도 현재 usort와 친구의 구현이 "보다 작음"과 "같음"을 동일하게 처리하기 때문에 향후 PHP 버전에서 계속 작동하지는 않을 것입니다. 정렬을 안정적으로 만들려고하면 (즉, 동일한 요소를 불필요하게 움직이지 않으면) 깨집니다.
Mark Amery 2016 년

또한 순차적 숫자 배열로 처리 할 때 혼란스럽고 예기치 않은 키와 값 사이의 연관성을 유지하므로 여기 usort보다 더 적합 합니다. 예를 들어, 호출 후 위 의 색인은 순서대로 2, 0 및 1입니다. 어떤 이유로 든 원하는 경우가 아니라면 배열을 다시 색인화하고 다시 정렬하는을 사용 하는 것이 더 편할 것입니다. uasortuasort$arrayuasortusort
Mark Amery 2016 년

5

100 000 레코드에서 테스트되었습니다 : 초 단위의 시간 (funciton microtime으로 계산). 키 위치 정렬시 고유 한 값에만 해당됩니다.

@Josh Davis의 기능 솔루션 : 소요 시간 : 1.5768740177155

광산 솔루션 : 소요 시간 : 0.094044923782349

해결책:

function SortByKeyValue($data, $sortKey, $sort_flags=SORT_ASC)
{
    if (empty($data) or empty($sortKey)) return $data;

    $ordered = array();
    foreach ($data as $key => $value)
        $ordered[$value[$sortKey]] = $value;

    ksort($ordered, $sort_flags);

    return array_values($ordered); *// array_values() added for identical result with multisort*
}

7
그러나 고유 한 정렬 키에 대한 요구 사항은 일종의 거래 차단기입니다. 키가 될 수있는 고유 한 정렬 값이 있다면 질문을 시작합니다. 왜 그 키로 배열을 구성하면 안될까요? OP 시나리오에서는 가격이 같은 두 품목이 불가능하다고 상상하기 어렵습니다 . 이 솔루션을 사용하면 정렬 된 결과 집합에서 배열의 항목이 신비 롭고 조용히 사라집니다.
Chris Baker

@Chris Baker, 당신 말이 맞아요. 이것은 고유 한 값에 대해서만 작동합니다. 그러나이 솔루션은 매우 빠르게 작동하므로 속도가 그것을 만들고 사용하는 이유였습니다. 현재 실제가 아닐 수도 있습니다. PHP 7.1.x로 테스트해야합니다.
Nefelim

4

나는 이렇게 사용 uasort한다

<?php
$users = [
    [
        'username' => 'joe',
        'age' => 11
    ],
    [
        'username' => 'rakoto',
        'age' => 21
    ],
    [
        'username' => 'rabe',
        'age' => 17
    ],
    [
        'username' => 'fy',
        'age' => 19
    ],    
];


uasort($users, function ($item, $compare) {
    return $item['username'] >= $compare['username']; 
});

var_dump($users);

3

이 기능은 재사용 가능합니다 :

function usortarr(&$array, $key, $callback = 'strnatcasecmp') {
    uasort($array, function($a, $b) use($key, $callback) {
        return call_user_func($callback, $a[$key], $b[$key]);
    });
}

기본적으로 문자열 값에서 잘 작동하지만 모든 값이 숫자 인 경우 숫자 비교 함수에 콜백을 사용해야합니다.


이것을 호출 usortarr하지만 uasort대신에 호출하십시오 usort. 아마도 약간 혼란 스럽습니다. 후자는-질문에 나타난 것과 같이 숫자 인덱스가있는 순차 배열의 경우 실제로 원하는 것입니다.
Mark Amery 2016 년

2

고유 한 비교 함수를 정의한 다음 usort 를 사용하려고 할 수 있습니다 .


예. 해결책을 찾지 못하면 그렇게 할 것입니다. 나는 이것을 달성하기 위해 일종의 이상한 매개 변수를 추가 할 수 있다고 확신합니다. 그래도 당신의 생각에 감사드립니다!
Matt

2

여기 오래 전에 발견하고 조금 정리 한 방법이 있습니다. 이것은 훌륭하게 작동하며 객체를 수락하도록 신속하게 변경할 수 있습니다.

/**
 * A method for sorting arrays by a certain key:value.
 * SortByKey is the key you wish to sort by
 * Direction can be ASC or DESC.
 *
 * @param $array
 * @param $sortByKey
 * @param $sortDirection
 * @return array
 */
private function sortArray($array, $sortByKey, $sortDirection) {

    $sortArray = array();
    $tempArray = array();

    foreach ( $array as $key => $value ) {
        $tempArray[] = strtolower( $value[ $sortByKey ] );
    }

    if($sortDirection=='ASC'){ asort($tempArray ); }
        else{ arsort($tempArray ); }

    foreach ( $tempArray as $key => $temp ){
        $sortArray[] = $array[ $key ];
    }

    return $sortArray;

}

객체 정렬 방법을 변경하려면 다음 줄을 변경하면됩니다.

$tempArray[] = strtolower( $value[ $sortByKey ] );$tempArray[] = strtolower( $value->$sortByKey );

방법을 간단하게 실행하려면

sortArray($inventory,'price','ASC');


이 접근법은 효과가 있지만 Josh Davis의 답변 ( array_multisort) 또는 내 () 보다 약간 간결 usort하지 않으며 그 대가로 이점을 제공하지 않는 것 같습니다.
Mark Amery

1
//Just in one line custom function
function cmp($a, $b)
{
return (float) $a['price'] < (float)$b['price'];
}
@uasort($inventory, "cmp");
print_r($inventory);

//result

Array
(
[2] => Array
    (
        [type] => pork
        [price] => 5.43
    )

[0] => Array
    (
        [type] => fruit
        [price] => 3.5
    )

[1] => Array
    (
        [type] => milk
        [price] => 2.9
    )

)

1

이 시도:

$prices = array_column($inventory, 'price');
array_multisort($prices, SORT_DESC, $inventory);
print_r($inventory);

안녕하세요, stackoverflow에 오신 것을 환영합니다. 답변 주셔서 감사합니다. 이 코드가 질문에 대답 할 수는 있지만, 문제가 해결 된 방법과 해결 방법에 대한 설명을 추가 할 수 있습니까? 이것은 미래 독자들이 귀하의 답변을 더 잘 이해하고 그로부터 배우는 데 도움이 될 것입니다.
Plutian

0

완전한 동적 함수 연관 배열 정렬을 위해 여기로 뛰어 들었고 http://php.net/manual/en/function.sort.php 에서이 놀라운 기능을 발견했습니다 . . 이 기능은 지정된 키를 사용하여 오름차순 및 내림차순으로 정렬되는 매우 동적입니다.

특정 키를 기준으로 배열을 정렬하는 간단한 기능입니다. 인덱스 연결 유지

<?php

function array_sort($array, $on, $order=SORT_ASC)
{
    $new_array = array();
    $sortable_array = array();

    if (count($array) > 0) {
        foreach ($array as $k => $v) {
            if (is_array($v)) {
                foreach ($v as $k2 => $v2) {
                    if ($k2 == $on) {
                        $sortable_array[$k] = $v2;
                    }
                }
            } else {
                $sortable_array[$k] = $v;
            }
        }

        switch ($order) {
            case SORT_ASC:
                asort($sortable_array);
            break;
            case SORT_DESC:
                arsort($sortable_array);
            break;
        }

        foreach ($sortable_array as $k => $v) {
            $new_array[$k] = $array[$k];
        }
    }

    return $new_array;
}

$people = array(
    12345 => array(
        'id' => 12345,
        'first_name' => 'Joe',
        'surname' => 'Bloggs',
        'age' => 23,
        'sex' => 'm'
    ),
    12346 => array(
        'id' => 12346,
        'first_name' => 'Adam',
        'surname' => 'Smith',
        'age' => 18,
        'sex' => 'm'
    ),
    12347 => array(
        'id' => 12347,
        'first_name' => 'Amy',
        'surname' => 'Jones',
        'age' => 21,
        'sex' => 'f'
    )
);

print_r(array_sort($people, 'age', SORT_DESC)); // Sort by oldest first
print_r(array_sort($people, 'surname', SORT_ASC)); // Sort by surname

-1
$arr1 = array(

    array('id'=>1,'name'=>'aA','cat'=>'cc'),
    array('id'=>2,'name'=>'aa','cat'=>'dd'),
    array('id'=>3,'name'=>'bb','cat'=>'cc'),
    array('id'=>4,'name'=>'bb','cat'=>'dd')
);

$result1 = array_msort($arr1, array('name'=>SORT_DESC);

$result2 = array_msort($arr1, array('cat'=>SORT_ASC);

$result3 = array_msort($arr1, array('name'=>SORT_DESC, 'cat'=>SORT_ASC));


function array_msort($array, $cols)
{
    $colarr = array();
    foreach ($cols as $col => $order) {
    $colarr[$col] = array();
    foreach ($array as $k => $row) { $colarr[$col]['_'.$k] = strtolower($row[$col]); }
}

$eval = 'array_multisort(';

foreach ($cols as $col => $order) {
    $eval .= '$colarr[\''.$col.'\'],'.$order.',';
}

$eval = substr($eval,0,-1).');';
eval($eval);
$ret = array();
foreach ($colarr as $col => $arr) {
    foreach ($arr as $k => $v) {
        $k = substr($k,1);
        if (!isset($ret[$k])) $ret[$k] = $array[$k];
        $ret[$k][$col] = $array[$k][$col];
    }
}
return $ret;


} 

이 코드 스 니펫은 문제를 해결할 수 있지만 설명을 포함하면 게시물의 품질을 향상시키는 데 실제로 도움이됩니다. 앞으로 독자에게 질문에 대한 답변을 제공하고 있으며 해당 사람들이 귀하의 코드 제안 이유를 모를 수도 있습니다. 코드와 설명의 가독성을 떨어 뜨리므로 설명 주석으로 코드를 혼동하지 마십시오!
Goodbye StackExchange

-5

이 시도:

asort($array_to_sort, SORT_NUMERIC);

참조를 위해 이것을 참조하십시오 : http://php.net/manual/en/function.asort.php

다양한 정렬 플래그를 여기에서 참조하십시오 : http://www.php.net/manual/en/function.sort.php


이것은 다차원 배열에서는 작동하지 않지만 다른 문제를 해결하는 데 도움이되었습니다. :)
schellmax

4
사전 목록을 특정 사전 키로 정렬하는 데 사용할 수 없으므로 제기 된 질문에 대답하지 않습니다.
Mark Amery
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.