Si j'ai un Illuminate \ Support \ Collection, comment puis-je trier par plusieurs propriétés avec asc et desc? (Ceci est une hypothèse simple - pas du tout à la recherche de conseils sur la création de requêtes.)

$collection = User::all(); // not looking for User::orderBy()->get() solutions.  Read the question.
$sorting_insructions = [
    ['column'=>'first_name', 'order'=>'asc'],
    ['column'=>'date_of_birth', 'order'=>'desc'],
];
$collection->sort(function($a,$b) use ($sorting_instructions){
    // something...
});
2
Tarek Adam 16 nov. 2017 à 02:33

4 réponses

Meilleure réponse

Quiconque l'utilise, gardez à l'esprit que vous devrez le modifier selon que vous utilisez une collection d'objets ou des tableaux associatifs. Cela devrait être un ajustement facile. Changez simplement les éléments $ a [] / $ b [] en $ a-> et $ b->

    public static function multiPropertySort(Collection $collection, array $sorting_instructions){

        return $collection->sort(function ($a, $b) use ($sorting_instructions){

            //stuff starts here to answer question...

            foreach($sorting_instructions as $sorting_instruction){

                $a[$sorting_instruction['column']] = (isset($a[$sorting_instruction['column']])) ? $a[$sorting_instruction['column']] : '';
                $b[$sorting_instruction['column']] = (isset($b[$sorting_instruction['column']])) ? $b[$sorting_instruction['column']] : '';

                if(empty($sorting_instruction['order']) or strtolower($sorting_instruction['order']) == 'asc'){
                    $x = ($a[$sorting_instruction['column']] <=> $b[$sorting_instruction['column']]);
                }else{
                    $x = ($b[$sorting_instruction['column']] <=> $a[$sorting_instruction['column']]);

                }

                if($x != 0){
                    return $x;
                }

            }

            return 0;

        })->values();
    }
1
Tarek Adam 26 mai 2019 à 18:19

Si vous utilisez Eloquent pour obtenir votre instance de collection, il serait bien préférable d'utiliser méthode orderBy dans votre requête, en particulier si les colonnes ont été indexées:

$sorting_insructions = [
    ['column'=>'first_name', 'order'=>'asc'],
    ['column'=>'date_of_birth', 'order'=>'desc'],
];

$collection = App\User::query();

foreach ($sorting_insructions as $value) {

    $collection->orderBy($value['column'], $value['order']);

}

$users = $collection->get();

MODIFIER Comme la question a été modifiée pour indiquer que le tri doit être utilisé en dehors du générateur de requêtes, je pense que le chaînage sortBy et sortByDesc en sens inverse order from $sorting_insructions donne le même résultat:

$collection = App\User::all();

$sorting_insructions = [
    ['column'=>'first_name', 'order'=>'asc'],
    ['column'=>'date_of_birth', 'order'=>'desc'],
];

for ($i = count($sorting_insructions) - 1; $i >= 0 ; $i--) { 

    extract($sorting_insructions[i]);

    if ( $order === 'asc') {
        $collection = $collection->sortBy( $column );
    } else {
        $collection = $collection->sortByDesc( $column );
    }

}
2
YouneL 16 nov. 2017 à 18:59

C'est un moment après que cette question a été posée et je ne suis pas sûr que ce soit la meilleure façon de le faire (à cause de nombreuses boucles), mais c'est vraiment un code court.

$sortDrives = $drives->groupBy('date')->sortBy('date');
    $lastDrive = $sortDrives->map(function ($item, $key) {
    return $item->sortBy('odometer');
})->collapse()->last();

J'ai collé mon propre exemple car la logique est assez simple pour le modifier

Explication:

Disons: date1 et odomètre1

Au début, vous tournez:

[
    0 => ['date' => date2, 'odometer' => odometer3],
    1 => ['date' => date1, 'odometer' => odometer2],
    2 => ['date' => date1, 'odometer' => odometer1],
]

Dans:

[
    date2 => [
        0 => ['date' => date2, 'odometer' => odometer3]
    ],
    date1 => [
        0 => ['date' => date1, 'odometer' => odometer2],
        1 => ['date' => date1, 'odometer' => odometer1]
    ]
]

Ensuite, vous le triez par nouvelle clé et obtenez:

[
    date1 => ...
    date2 => ...
]

Après cela, vous triez par clé # 2 à l'intérieur de chaque clé de date du tableau pointe vers:

[
    date1 => [
        0 => ['date' => date1, 'odometer' => odometer1],
        1 => ['date' => date1, 'odometer' => odometer2]
    ]
    date2 => [
        0 => ['date' => date2, 'odometer' => odometer3]
    ],
]

Enfin, vous mettez en collision tous ces tableaux ensemble (en supprimant la clé de date) et obtenez:

[
    0 => ['date' => date1, 'odometer' => odometer1],
    1 => ['date' => date1, 'odometer' => odometer2],
    2 => ['date' => date2, 'odometer' => odometer3]
]
-1
NoOorZ24 23 mars 2018 à 06:14
public static function multiPropertySort(
    Collection $collection,
    array $rules
)
{
    return $collection->sort(
        function ($a, $b) use ($rules) {
            foreach($rules as $rule){
                $sortColumn = array_get($rule, 'column');

                array_set(
                    $a,
                    $sortColumn,
                    array_get($a, $sortColumn, '')
                );

                array_set(
                    $b,
                    $sortColumn,
                    array_get($b, $sortColumn, '')
                );

                if ($sortOrder = array_get($rule, 'order', 'asc')) {
                    $x = (array_get($a, $sortColumn) <=> array_get($b, $sortColumn));
                } else {
                    $x = (array_get($b, $sortColumn) <=> array_get($a, $sortColumn));
                }

                if ($x != 0) {
                    return $x;
                }
            }

            return 0;
        }
    );
}

Imaginons quelque chose d'impératif ...

0
Piterden 16 nov. 2017 à 09:14
47319120