web-dev-qa-db-ja.com

PHPで配列とデータをソートするにはどうすればよいですか?

この質問は、PHPでの配列の並べ替えに関する質問の参照用です。あなたの特定のケースはユニークで新しい質問に値するものであると考えるのは簡単ですが、ほとんどは実際にはこのページの解決策の1つの小さなバリエーションです。

あなたの質問がこの質問の複製として閉じられた場合、それが以下のすべてと著しく異なる理由を説明できる場合にのみ、あなたの質問が再開されるように依頼してください。

PHPで配列をソートするにはどうすればよいですか?
PHPでcomplex配列をソートするにはどうすればよいですか?
PHPでオブジェクトの配列をソートするにはどうすればよいですか?


  1. 基本的な1次元配列、多次元配列を含む、オブジェクトの配列を含む、1つの配列を別の配列に基づいて並べ替えを含む

  2. SPLによる並べ替え

  3. 安定したソート

PHPの既存の関数を使用した実用的な回答については、ソートアルゴリズムに関するアカデミックな詳細な回答(PHPの関数を実装し、必要なmay)を参照してください。本当に複雑なケースについては、2をご覧ください。

275
deceze

さて、ほとんどの基本的な方法はすでに deceze でカバーされています。他の種類のソートを見てみます。

SPLによる並べ替え

SplHeap

class SimpleHeapSort extends SplHeap {
    public function compare($a, $b) {
        return strcmp($a, $b);
    }
}

// Let's populate our heap here (data of 2009)
$heap = new SimpleHeapSort();
$heap->insert("a");
$heap->insert("b");
$heap->insert("c");

echo implode(PHP_EOL, iterator_to_array($heap));

出力

c
b
a

SplMaxHeap

SplMaxHeapクラスは、ヒープの主要な機能を提供し、最大を維持します。

$heap = new SplMaxHeap();
$heap->insert(1);
$heap->insert(2);
$heap->insert(3);

SplMinHeap

SplMinHeapクラスは、ヒープの主要な機能を提供し、最小を最上位に保ちます。

$heap = new SplMinHeap ();
$heap->insert(3);
$heap->insert(1);
$heap->insert(2);

その他の種類の並べ替え

バブルソート

バブルソートに関するウィキペディアの記事:

バブルソートは、誤ってシンクソートと呼ばれることもありますが、ソートするリストを繰り返しステップスルーし、隣接するアイテムの各ペアを比較し、順序が間違っている場合はそれらを交換することで機能する単純なソートアルゴリズムです。リストがソートされることを示すスワップが不要になるまで、リストのパスが繰り返されます。このアルゴリズムの名前は、小さな要素が「バブル」してリストの先頭に到達する方法から付けられます。要素を操作するために比較のみを使用するため、比較ソートです。アルゴリズムは単純ですが、他のほとんどのソートアルゴリズムは大きなリストに対してより効率的です。

function bubbleSort(array $array) {
    $array_size = count($array);
    for($i = 0; $i < $array_size; $i ++) {
        for($j = 0; $j < $array_size; $j ++) {
            if ($array[$i] < $array[$j]) {
                $tem = $array[$i];
                $array[$i] = $array[$j];
                $array[$j] = $tem;
            }
        }
    }
    return $array;
}

選択ソート

選択ソートに関するウィキペディアの記事:

コンピュータサイエンスでは、選択ソートはソートアルゴリズム、特にインプレース比較ソートです。 O(n2)の時間の複雑さがあるため、大きなリストでは非効率になり、一般に同様の挿入ソートよりもパフォーマンスが低下します。選択ソートは単純であるために注目されており、特定の状況、特に補助メモリが限られている場合、より複雑なアルゴリズムよりもパフォーマンスが優れています。

function selectionSort(array $array) {
    $length = count($array);
    for($i = 0; $i < $length; $i ++) {
        $min = $i;
        for($j = $i + 1; $j < $length; $j ++) {
            if ($array[$j] < $array[$min]) {
                $min = $j;
            }
        }
        $tmp = $array[$min];
        $array[$min] = $array[$i];
        $array[$i] = $tmp;
    }
    return $array;
}

挿入ソート

挿入ソートに関するウィキペディアの記事:

挿入ソートは、最終的なソート済み配列(またはリスト)を一度に1項目作成する単純なソートアルゴリズムです。大規模なリストでは、クイックソート、ヒープソート、マージソートなどのより高度なアルゴリズムよりもはるかに効率的ではありません。ただし、挿入ソートにはいくつかの利点があります。

function insertionSort(array $array) {
    $count = count($array);
    for($i = 1; $i < $count; $i ++) {

        $j = $i - 1;
        // second element of the array
        $element = $array[$i];
        while ( $j >= 0 && $array[$j] > $element ) {
            $array[$j + 1] = $array[$j];
            $array[$j] = $element;
            $j = $j - 1;
        }
    }
    return $array;
}

シェルソート

シェルソートに関するウィキペディアの記事:

Shellsortは、ShellソートまたはShellのメソッドとも呼ばれ、インプレース比較ソートです。挿入またはバブルソートなどの交換ソートを一般化し、隣接するエレメントで終了する前に、離れているエレメントとエレメントの比較および交換を開始します。

function shellSort(array $array) {
    $gaps = array(
            1,
            2,
            3,
            4,
            6
    );
    $gap = array_pop($gaps);
    $length = count($array);
    while ( $gap > 0 ) {
        for($i = $gap; $i < $length; $i ++) {
            $tmp = $array[$i];
            $j = $i;
            while ( $j >= $gap && $array[$j - $gap] > $tmp ) {
                $array[$j] = $array[$j - $gap];
                $j -= $gap;
            }
            $array[$j] = $tmp;
        }
        $gap = array_pop($gaps);
    }
    return $array;
}

コームソート

Comb sortに関するWikipediaの記事:

櫛の並べ替えは、1980年にWlodzimierz Dobosiewiczによって最初に設計された比較的単純な並べ替えアルゴリズムです。その後、1991年にStephen LaceyとRichard Boxによって再発見されました。櫛の並べ替えはバブル並べ替えを改善します。

function combSort(array $array) {
    $gap = count($array);
    $swap = true;
    while ( $gap > 1 || $swap ) {
        if ($gap > 1)
            $gap /= 1.25;
        $swap = false;
        $i = 0;
        while ( $i + $gap < count($array) ) {
            if ($array[$i] > $array[$i + $gap]) {
                // swapping the elements.
                list($array[$i], $array[$i + $gap]) = array(
                        $array[$i + $gap],
                        $array[$i]
                );
                $swap = true;
            }
            $i ++;
        }
    }
    return $array;
}

ソートをマージ

マージの並べ替えに関するウィキペディアの記事:

コンピューターサイエンスでは、マージソート(一般的にスペルマージソートとも呼ばれます)は、O(n log n)比較ベースのソートアルゴリズムです。ほとんどの実装は安定したソートを生成します。つまり、実装はソートされた出力で等しい要素の入力順序を保持します

function mergeSort(array $array) {
    if (count($array) <= 1)
        return $array;

    $left = mergeSort(array_splice($array, floor(count($array) / 2)));
    $right = mergeSort($array);

    $result = array();

    while ( count($left) > 0 && count($right) > 0 ) {
        if ($left[0] <= $right[0]) {
            array_Push($result, array_shift($left));
        } else {
            array_Push($result, array_shift($right));
        }
    }
    while ( count($left) > 0 )
        array_Push($result, array_shift($left));

    while ( count($right) > 0 )
        array_Push($result, array_shift($right));

    return $result;
}

クイックソート

クイックソートに関するウィキペディアの記事:

クイックソート、またはパーティション交換ソートは、Tony Hoareが開発したソートアルゴリズムで、平均してO(n log n)比較してn個のアイテムをソートします。最悪の場合、O(n2)の比較が行われますが、この動作はまれです。

function quickSort(array $array) {
    if (count($array) == 0) {
        return $array;
    }
    $pivot = $array[0];
    $left = $right = array();
    for($i = 1; $i < count($array); $i ++) {
        if ($array[$i] < $pivot) {
            $left[] = $array[$i];
        } else {
            $right[] = $array[$i];
        }
    }
    return array_merge(quickSort($left), array(
            $pivot
    ), quickSort($right));
}

順列ソート

置換ソートに関するウィキペディアの記事:

並べ替え並べ替え。並べ替えられたものが見つかるまで、入力配列/リストの可能な並べ替えを生成することによって続行します。

function permutationSort($items, $perms = array()) {
    if (empty($items)) {
        if (inOrder($perms)) {
            return $perms;
        }
    } else {
        for($i = count($items) - 1; $i >= 0; -- $i) {
            $newitems = $items;
            $newperms = $perms;
            list($foo) = array_splice($newitems, $i, 1);
            array_unshift($newperms, $foo);
            $res = permutationSort($newitems, $newperms);
            if ($res) {
                return $res;
            }
        }
    }
}

function inOrder($array) {
    for($i = 0; $i < count($array); $i ++) {
        if (isset($array[$i + 1])) {
            if ($array[$i] > $array[$i + 1]) {
                return False;
            }
        }
    }
    return True;
}

基数ソート

Radixソートに関するウィキペディアの記事:

コンピュータサイエンスでは、基数ソートは、同じ重要な位置と値を共有する個々の数字でキーをグループ化することにより、整数キーでデータをソートする非比較整数ソートアルゴリズムです。

// Radix Sort for 0 to 256
function radixSort($array) {
    $n = count($array);
    $partition = array();

    for($slot = 0; $slot < 256; ++ $slot) {
        $partition[] = array();
    }

    for($i = 0; $i < $n; ++ $i) {
        $partition[$array[$i]->age & 0xFF][] = &$array[$i];
    }

    $i = 0;

    for($slot = 0; $slot < 256; ++ $slot) {
        for($j = 0, $n = count($partition[$slot]); $j < $n; ++ $j) {
            $array[$i ++] = &$partition[$slot][$j];
        }
    }
    return $array;
}
137
Baba

安定したソート

次のような配列があるとしましょう:

['Kale', 'Kaleidoscope', 'Aardvark', 'Apple', 'Leicester', 'Lovely']

そして今、あなたは最初の文字だけでソートしたい:

usort($array, function($a, $b) {
    return strcmp($a[0], $b[0]);
});

結果は次のとおりです。

['Apple', 'Aardvark', 'Kale', 'Kaleidoscope', 'Lovely', 'Leicester']

ソートは安定していませんでした!

鋭いオブザーバーは、配列ソートアルゴリズム(QuickSort)が安定した結果を生成せず、同じ最初の文字の単語間の元の順序が保持されないことに気付いたかもしれません。このケースは簡単であり、文字列全体を比較する必要がありましたが、ユースケースがより複雑であると仮定しましょう。たとえば、異なるフィールドでの2つの連続したソートは、お互いの作業をキャンセルしません。

シュワルツ変換

Schwartzian変換 は、decorate-sort-undecorateイディオムとも呼ばれ、本質的に不安定なソートアルゴリズムで安定したソートを行います。

最初に、主キー(値)と二次キー(そのインデックスまたは位置)で構成される別の配列で各配列要素を修飾します。

array_walk($array, function(&$element, $index) {
    $element = array($element, $index); // decorate
});

これにより、配列は次のように変換されます。

[
    ['Kale', 0], ['Kaleidoscope', 1], 
    ['Aardvark', 2], ['Apple', 3], 
    ['Leicester', 4], ['Lovely', 5]
]

次に、比較ステップを調整します。最初の文字を再度比較しますが、同じ場合は、2次キーを使用して元の順序を保持します。

usort($array, function($a, $b) {
    // $a[0] and $b[0] contain the primary sort key
    // $a[1] and $b[1] contain the secondary sort key
    $tmp = strcmp($a[0][0], $b[0][0]);

    if ($tmp != 0) {
        return $tmp; // use primary key comparison results
    }

    return $a[1] - $b[1]; // use secondary key
});

その後、装飾を解除します。

array_walk($array, function(&$element) {
    $element = $element[0];
});

最終結果:

['Aardvark', 'Apple', 'Kale', 'Kaleidoscope', 'Leicester', 'Lovely']

再利用はどうですか?

変換された配列要素を操作するには、比較関数を書き直す必要がありました。繊細な比較関数を編集したくない場合があるため、比較関数のラッパーを次に示します。

function stablecmp($fn)
{
    return function($a, $b) use ($fn) {
        if (($tmp = call_user_func($fn, $a[0], $b[0])) != 0) {
            return $tmp;
        } else {
            return $a[1] - $b[1];
        }
    };
}

この関数を使用してソート手順を記述しましょう。

usort($array, stablecmp(function($a, $b) {
    return strcmp($a[0], $b[0]);
}));

出来上がり!元の比較コードが戻ってきました。

44
Ja͢ck

クロージャを使用するPHP 5.3では、クロージャを使用してソートの順序を決定することもできます。

たとえば、$ arrayがmonthプロパティを含むオブジェクトの配列であると仮定します。

 $orderArray = array("Jan","Feb","Mar","Apr","May","June","July","Aug","Sept","Oct","Nov","Dec");

 usort($array, function($a, $b) use ($orderArray){
       return array_search($a->month, $orderArray) - array_search($b->month, $orderArray);
 }); 
15
Orangepill

LINQ

.NETでは、特にオブジェクトを複数のフィールドで並べ替える必要がある場合、LINQは並べ替えに頻繁に使用され、比較関数よりもはるかに優れた構文を提供します。 YaLinqo library *を含む、LINQのPHPへのポートがいくつかあります。これにより、複雑な比較関数を記述することなく、1行で配列をソートできます。

$sortedByName         = from($objects)->orderBy('$v->name');
$sortedByCount        = from($objects)->orderBy('$v->count');
$sortedByCountAndName = from($objects)->orderBy('$v->count')->thenBy('$v->name');

比較は、たとえば次のように2番目の引数としてコールバックを渡すことでさらにカスタマイズできます。

$sortedByFilenameNat  = from($objects)->orderBy('$v->filename', 'strnatcmp');

ここで、'$v->count'function ($v) { return $v->count; }の省略形です(どちらも使用できます)。これらのメソッドチェーンは反復子を返します。必要に応じて、最後に->toArray()を追加することで、反復子を配列に変換できます。

内部的に、orderByおよび関連するメソッドは、適切な配列ソート関数(uasortkrsortmultisortusortなど)を呼び出します。

LINQには、フィルタリング、グループ化、結合、集計など、SQLに触発された多くのメソッドが含まれています。データベースに依存せずに配列やオブジェクトの複雑な変換を実行する必要がある場合に最適です。

*私が開発しました。詳細および他のLINQポートとの比較については、readmeを参照してください。

9
Athari

キー値による多次元ソート

キー値による多次元配列の自然な並べ替えと元の順序の維持(メインキーをシャッフルしないでください):

function multisortByKeyValue( $k, $arr ) {
    $ids   = array();
    $index = 1;

    foreach ( $arr as $key => $row ) {
        $ids[ $key ] = intval( $row[ $k ] ) . '-' . $index . '-' . $key;
        $index ++;
    }

    natsort( $ids );

    $arr = array_merge( $ids, $arr );

    return $arr;
}

テストケース:

$arr = array(
    'id1' => array(
        'label'    => 'ID 1',
        'priority' => 30,
    ),
    'id2' => array(
        'label'    => 'ID 2',
        'priority' => 70,
    ),
    'id3' => array(
        'label'    => 'ID 3',
        'priority' => 20,
    ),
    'id4' => array(
        'label'    => 'ID 4',
        'priority' => 30,
    ),
);

$sorted = multisortByKeyValue( 'priority', $arr );

// $sorted equals to:
/*
array (
  'id3' => array (
    'label' => 'ID 3',
    'priority' => 20,
  ),
  'id1' => array (
    'label' => 'ID 1',
    'priority' => 30,
  ),
  'id4' => array (
    'label' => 'ID 4',
    'priority' => 30,
  ),
  'id2' => array (
    'label' => 'ID 2',
    'priority' => 70,
  ),
)
*/
3
Andrei Surdu

sorted function from Nspl で配列をソートすると非常に便利です:

基本的な並べ替え

// Sort array
$sorted = sorted([3, 1, 2]);

// Sort array in descending order
$sortedDesc = sorted([3, 1, 2], true);

関数結果によるソート

// Sort array by the result of a given function (order words by length)
$sortedByLength = sorted(['bc', 'a', 'abc'], 'strlen');
$sortedByLengthDesc = sorted(['bc', 'a', 'abc'], true, 'strlen');

// Sort array by the result of user-defined function (order words by the 1st character)
$sortedByTheFirstCharacter = sorted(['bc', 'a', 'abc'], function($v) { return $v[0]; }); 

// Which is the same as
$sortedByTheFirstCharacter = sorted(['bc', 'a', 'abc'], itemGetter(0));
$sortedByTheFirstCharacterDesc = sorted(['bc', 'a', 'abc'], true, itemGetter(0));

// itemGetter(0) returns a function which takes an argument with access by index/key
// and returns the value at index 0

多次元配列のソート

// Sort multidimensional array (sort list of users by their names)
$users = [
    array('name' => 'Robert', 'age' => 20),
    array('name' => 'Alex', 'age' => 30),
    array('name' => 'Jack', 'age' => 25),
];
$sortedByName = sorted($users, itemGetter('name'));
$sortedByNameDesc = sorted($users, true, itemGetter('name'));

// itemGetter('name') returns a function which takes an argument with access by index/key
// and returns the value of the 'name' key

オブジェクトの配列のソート

// Lets assume we have class User(name, age) with properties name and age
// and public methods getName() and getAge()
$users = [
    new User('Robert', 20),
    new User('Alex', 30),
    new User('Jack', 25),
];

// Sort list of objects by property value (sort list of users by their name)
$sortedByName = sorted($users, propertyGetter('name'));
$sortedByNameDesc = sorted($users, true, propertyGetter('name'));

// propertyGetter('name') returns a function which takes an object
// and returns the value of its 'name' property

// Sort list of objects by method result (sort list of users by their age)
$sortedByAge = sorted($users, methodCaller('getAge'));
$sortedByAgeDesc = sorted($users, true, methodCaller('getAge'));

// methodCaller('getAge') returns a function which takes an object
// and returns the result of its getAge() method

比較関数によるソート

// Sort with a comparison function (order words lexicographically with strcmp)
$sortedLexicographically = sorted(['bc', 'a', 'abc'], false, null, 'strcmp');

// Sort with user-defined comparison function (order words by the 1st character)
$sortedByTheFirstCharacter = sorted(['bc', 'a', 'abc'], false, null, function($v1, $v2) {
    return chr($v1[0]) - chr($v2[0]);
});

これらすべての例を見ることができます here

2

キー値で並べ替える場合は、エレガントで明確な1行で行うことができます。これは価格の昇順で注文します。 array_multisortとarray_columnを使用します。

   Array([0] => Array ( [name] => eggs [price] => 1 ) [1] => Array ( [name] => coffee [price] => 9.99 ) [2] => Array ( [name] => rice [price] => 4.04 ) )

   array_multisort (array_column($array, 'price'), SORT_ASC, $array);

生産する

     Array ( [0] => Array ( [name] => eggs [price] => 1 ) [1] => Array ( [name] => rice [price] => 4.04 ) [2] => Array ( [name] => coffee [price] => 9.99 ) )
0
GAV

配列を並べ替えるにはいくつかの方法があります。そのtask.fistを実行するためのいくつかのメソッドに言及し、「$ numbers」と呼ばれる整数配列を提供します。

$number = array(8,9,3,4,0,1,2);

これは、配列を作成する通常の方法です。その配列を昇順でソートしたいとします。そのためには、「sort()」メソッドを使用できます。

<?php

    $number = array(8,9,3,4,0,1,2);
    sort($number);

   foreach ($number as $value) {
       echo $value."  ";
   }
?>

次に、その出力を検討します。

enter image description here

印刷された数値配列がソートされていることがわかります。その番号配列を降順に並べ替えたい場合は、そのタスクに 'rsort()'メソッドを使用できます。

<?php

     $number = array(8,9,3,4,0,1,2);
     rsort($number);

     foreach ($number as $value) {
        echo $value."  ";
     }
?>

出力を考慮してください。

enter image description here

今、配列は降順でソートされます。OK、連想配列を考えてみましょう。連想配列を与えます(連想配列とは、各インデックスが一意のキー値を持つ配列です)。

$number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);

だから、私はこの配列をその値に応じて昇順でソートしたいと思います。'asort() 'メソッドを使用できます。

<?php

   $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
   asort($number);

   foreach ($number as $value) {
      echo $value."  ";
    }
?>

値に従って降順でソートする場合は、「arsort()」メソッドを使用できます。キー値に従ってその配列をソートするとします。この場合、「ksort()」メソッドを使用できます。

<?php

     $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
     ksort($number);

     foreach ($number as $value) {
         echo $value."  ";
     }
?>

次に、出力を検討します。 enter image description here

配列はキー値に従ってソートされます。キー値に従って降順で配列をソートする場合は、 'krsort()'メソッドを使用できます。

<?php

    $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
    krsort($number);

    foreach ($number as $value) {
       echo $value."  ";
    }
?>

これで、連想配列はキー値に従って降順にソートされます。出力を見てください。 enter image description here

これらは、phpで昇順または降順で配列をソートするためのいくつかのメソッドです。アイデアを得ることができることを願っています。ありがとう!

0
GT_hash