Подтвердить что ты не робот

Сортировка массива php массивов по индивидуальному заказу

У меня есть массив массивов:

Array ( 
    [0] => Array (
        [id] = 7867867,
        [title] = 'Some Title'),
    [1] => Array (
        [id] = 3452342,
        [title] = 'Some Title'),
    [2] => Array (
        [id] = 1231233,
        [title] = 'Some Title'),
    [3] => Array (
        [id] = 5867867,
        [title] = 'Some Title')
)

Необходимость идти в определенном порядке:

  • 3452342
  • 5867867
  • 7867867
  • 1231233

Как бы я это сделал? Я уже сортировал массивы и читал много других сообщений об этом, но они всегда основаны на сравнении (то есть valueA < valueB).

Помощь приветствуется.

4b9b3361

Ответ 1

Вы можете использовать usort(), чтобы точно определить способ сортировки массива. В этом случае массив $order может использоваться в функции сравнения.

В приведенном ниже примере используется closure, чтобы облегчить жизнь.

$order = array(3452342, 5867867, 7867867, 1231233);
$array = array(
    array('id' => 7867867, 'title' => 'Some Title'),
    array('id' => 3452342, 'title' => 'Some Title'),
    array('id' => 1231233, 'title' => 'Some Title'),
    array('id' => 5867867, 'title' => 'Some Title'),
);

usort($array, function ($a, $b) use ($order) {
    $pos_a = array_search($a['id'], $order);
    $pos_b = array_search($b['id'], $order);
    return $pos_a - $pos_b;
});

var_dump($array);

Ключом к этой работе является сопоставление значений, являющихся позициями id в массиве $order.

Функция сравнения работает путем нахождения позиций идентификаторов двух элементов для сравнения в массиве $order. Если $a['id'] предшествует $b['id'] в массиве $order, то возвращаемое значение функции будет отрицательным ($a меньше, так что "плавает" вверх). Если $a['id'] появляется после $b['id'], тогда функция возвращает положительное число ($a больше, поэтому "снижается" ).

Наконец, нет особых причин для использования закрытия; это просто мой путь к написанию этих видов отброшенных функций быстро. Он также может использовать обычную именованную функцию.

Ответ 2

Расширение ответа salathe для этого дополнительного требования:

Теперь, что происходит, когда я добавляю элементы в массив, а не в сортировку? я не заботятся о том, какой порядок они появляются, до тех пор, пока это происходит после что я указал.

Вам нужно добавить два дополнительных условия в функцию сортировки:

  • Элемент "dont care" должен считаться больше, чем "заботиться о".
  • Два элемента "не заботясь" должны считаться равными

Таким образом, пересмотренный код будет выглядеть следующим образом:

$order = array(
    3452342,
    5867867,
    7867867,
    1231233
);
$array = array(
    array("id" => 7867867, "title" => "Must Be #3"),
    array("id" => 3452342, "title" => "Must Be #1"),
    array("id" => 1231233, "title" => "Must Be #4"),
    array("id" => 5867867, "title" => "Must Be #2"),
    array("id" => 1111111, "title" => "Dont Care #1"),
    array("id" => 2222222, "title" => "Dont Care #2"),
    array("id" => 3333333, "title" => "Dont Care #3"),
    array("id" => 4444444, "title" => "Dont Care #4")
);
function custom_compare($a, $b){
    global $order;
    $a = array_search($a["id"], $order);
    $b = array_search($b["id"], $order);
    if($a === false && $b === false) { // both items are dont cares
        return 0;                      // a == b
    }
    else if ($a === false) {           // $a is a dont care item
        return 1;                      // $a > $b
    }
    else if ($b === false) {           // $b is a dont care item
        return -1;                     // $a < $b
    }
    else {
        return $a - $b;
    }
}
shuffle($array);  // for testing
var_dump($array); // before
usort($array, "custom_compare");
var_dump($array); // after

Вывод:

Before                         |  After
-------------------------------+-------------------------------
array(8) {                     |  array(8) {
  [0]=>                        |    [0]=>
  array(2) {                   |    array(2) {
    ["id"]=>                   |      ["id"]=>
    int(4444444)               |      int(3452342)
    ["title"]=>                |      ["title"]=>
    string(12) "Dont Care #4"  |      string(10) "Must Be #1"
  }                            |    }
  [1]=>                        |    [1]=>
  array(2) {                   |    array(2) {
    ["id"]=>                   |      ["id"]=>
    int(3333333)               |      int(5867867)
    ["title"]=>                |      ["title"]=>
    string(12) "Dont Care #3"  |      string(10) "Must Be #2"
  }                            |    }
  [2]=>                        |    [2]=>
  array(2) {                   |    array(2) {
    ["id"]=>                   |      ["id"]=>
    int(1231233)               |      int(7867867)
    ["title"]=>                |      ["title"]=>
    string(10) "Must Be #4"    |      string(10) "Must Be #3"
  }                            |    }
  [3]=>                        |    [3]=>
  array(2) {                   |    array(2) {
    ["id"]=>                   |      ["id"]=>
    int(1111111)               |      int(1231233)
    ["title"]=>                |      ["title"]=>
    string(12) "Dont Care #1"  |      string(10) "Must Be #4"
  }                            |    }
  [4]=>                        |    [4]=>
  array(2) {                   |    array(2) {
    ["id"]=>                   |      ["id"]=>
    int(5867867)               |      int(2222222)
    ["title"]=>                |      ["title"]=>
    string(10) "Must Be #2"    |      string(12) "Dont Care #2"
  }                            |    }
  [5]=>                        |    [5]=>
  array(2) {                   |    array(2) {
    ["id"]=>                   |      ["id"]=>
    int(2222222)               |      int(1111111)
    ["title"]=>                |      ["title"]=>
    string(12) "Dont Care #2"  |      string(12) "Dont Care #1"
  }                            |    }
  [6]=>                        |    [6]=>
  array(2) {                   |    array(2) {
    ["id"]=>                   |      ["id"]=>
    int(3452342)               |      int(3333333)
    ["title"]=>                |      ["title"]=>
    string(10) "Must Be #1"    |      string(12) "Dont Care #3"
  }                            |    }
  [7]=>                        |    [7]=>
  array(2) {                   |    array(2) {
    ["id"]=>                   |      ["id"]=>
    int(7867867)               |      int(4444444)
    ["title"]=>                |      ["title"]=>
    string(10) "Must Be #3"    |      string(12) "Dont Care #4"
  }                            |    }
}                              |  }

Ответ 3

Вам нужно определить свою собственную функцию сравнения и использовать usort или uasort, если вы хотите поддерживать ассоциацию индексов.

Ответ 4

Другие ответы, использующие методы с повторяющимися вызовами array_search(), не так эффективны, как могли бы быть. Путем реструктуризации/переворота поискового массива order вы можете полностью опустить все array_search() что сделает вашу задачу намного более эффективной и короткой. Я буду использовать самый современный "оператор космического корабля" (<=>), но более ранние методы будут работать одинаково для линии сравнения.

Метод № 1 - usort когда все значения id существуют в $order (Demo)

$order=array_flip([3452342,5867867,7867867,1231233]);  // restructure with values as keys, and keys as order (ASC)
// generating $order=[3452342=>0,5867867=>1,7867867=>2,1231233=>3];
$array=[
    ['id'=>7867867,'title'=>'Some Title'],
    ['id'=>3452342,'title'=>'Some Title'],
    ['id'=>1231233,'title'=>'Some Title'],
    ['id'=>5867867,'title'=>'Some Title']
];

usort($array,function($a,$b)use($order){
    return $order[$a['id']]<=>$order[$b['id']];
    // when comparing ids 3452342 & 1231233, the actual comparison is 0 vs 3
});
// uasort() if you want to preserve keys

var_export($array);

Метод № 2 - usort когда некоторые значения id не существуют в $order (Demo)
* обратите внимание, isset() является менее дорогим вызовом, чем array_search()

$order=array_flip([3452342,5867867,7867867,1231233]);  // restructure with values as keys, and keys as order (ASC)
// generating $order=[3452342=>0,5867867=>1,7867867=>2,1231233=>3];
$outlier=1+max($order);
// generating $outlier=4
$array=[
    ['id'=>7867867,'title'=>'Some Title'],
    ['id'=>3452342,'title'=>'Some Title'],
    ['id'=>'foo','title'=>'Some Title'],
    ['id'=>1231233,'title'=>'Some Title'],
    ['id'=>'bar','title'=>'Some Title'],
    ['id'=>5867867,'title'=>'Some Title']
];

usort($array,function($a,$b)use(&$order,$outlier){  // make $order modifiable with &
    if(!isset($order[$a['id']])){$order[$a['id']]=$outlier;}  // update lookup array with [id]=>[outlier number]
    if(!isset($order[$b['id']])){$order[$b['id']]=$outlier;}  // and again
    return $order[$a['id']]<=>$order[$b['id']];
});

var_export($array);

Альтернативный метод № 2 - используется для usort когда некоторые значения id не существуют в $order

... Я также хотел бы отметить, что в некоторых случаях избегание повторного двойного вызова isset() может быть менее привлекательным по сравнению с полной подготовкой массива $order перед вызовом usort().

Эта однострочная строка гарантирует отсутствие пропущенных значений id, что исключает необходимость чего-либо, кроме строки сравнения внутри функции сортировки. (Полная демонстрация фрагмента)

$order=array_replace(array_fill_keys(array_column($array,'id'),$outlier),$order);

Ответ 5

@salathe Для тех из вас, кто с трудом понимает, что делает salathe usort:

Каждый элемент в массиве $является "чемпионом" в турнире, который должен быть в начале нового массива (за исключением вместо того, чтобы быть номером один, они хотят быть числом 0).

$a является домашним чемпионом, а $b противником в матче.

$pos_a и $pos_b от обратного вызова - какие атрибуты будут использоваться в борьбе за чемпионов a и b. В этом случае этот атрибут является индексом идентификатора чемпиона в $order.

Затем идет бой при возвращении. Теперь мы посмотрим, лучше ли более или менее атрибут. В битве за битву домашний чемпион хочет отрицательное число, поэтому он может быть скорее в массиве. Выездной чемпион хочет получить положительное число. И должно быть 0, это галстук.

Итак, следуя этой аналогии, когда атрибут "Чемпионы" (индекс в $order) вычитается из атрибута home teams, чем больше атрибут away away, тем меньше вероятность выиграть, получив положительное число. Однако, если вы изменили способ использования атрибутов, теперь атрибут домашнего чемпиона вычитается из дальних чемпионов. В этом случае большее число для чемпиона в гостях, скорее всего, заставит его иметь конец матча в положительном числе.

Код будет выглядеть так:

note: код запускается много раз, так как у реального турнира много битв, чтобы решить, кто первым (т.е. 0/начало массива)

//tournament with goal to be first in array
    usort($champions, function ($home, $away) use ($order) {
        $home_attribute = array_search($a['id'], $order);
        $away_attribute = array_search($b['id'], $order);
        //fight with desired outcome for home being negative and away desiring positive
        return $home_attribute - $away_attribute;
    });

Ответ 6

Без сортировки вы также можете получить это.

Это не дубликат идентификатора;

<?php

    $order = array(3452342, 5867867, 7867867, 1231233);
    $array = array(
        array('id' => 7867867, 'title' => 'Some Title'),
        array('id' => 3452342, 'title' => 'Some Title'),
        array('id' => 1231233, 'title' => 'Some Title'),
        array('id' => 5867867, 'title' => 'Some Title'),
    );

    $order = array_flip($order);
    $array = array_column($array,null,"id");
    $result = array_replace($order,$array);
    var_dump(array_values($result));

С повторяющимся идентификатором,

<?php

    $order = array(3452342, 5867867, 7867867, 1231233);
    $array = array(
        array('id' => 7867867, 'title' => 'Some Title'),
        array('id' => 3452342, 'title' => 'Some Title'),
        array('id' => 1231233, 'title' => 'Some Title'),
        array('id' => 5867867, 'title' => 'Some Title'),
    );

    $order_dict = array_flip($order);
    $order_dict = array_combine($order,array_fill(0,count($order),[]));
    foreach($array as $item){
        $order_dict[$item["id"]][] = $item;
    }
    //$order_dict = array_filter($order_dict);  // if there is empty item on some id in $order array
    $result = [];
    foreach($order_dict as $items){
        foreach($items as $item){
            $result[] = $item;
        }
    }
    var_dump($result);

Ответ 7

Вот как я сортирую свой многомерный массив в порядке ASC на основе значения id:

$arrayFilter = array(
    array('product_tag' => 'xenia', 'id' => 4),
    array('product_tag' => 'worn',  'id' => 5),
    array('product_tag' => 'woven', 'id' => 3),
    array('product_tag' => 'nude', 'id' => 1)
);

for ($i = 0; $i < sizeof($arrayFilter); $i++) {
    for ($j=$i+1; $j < sizeof($arrayFilter); $j++) {
        if ($arrayFilter[$i]['id'] > $arrayFilter[$j]['id']) {
            $c = $arrayFilter[$i];
            $arrayFilter[$i] = $arrayFilter[$j];
            $arrayFilter[$j] = $c;
        }
    }
}
print_r($arrayFilter);

ВЫХОД:

Array
(
    [0] => Array
        (
            [product_tag] => nude
            [id] => 1
        )

    [1] => Array
        (
            [product_tag] => woven
            [id] => 3
        )

    [2] => Array
        (
            [product_tag] => xenia
            [id] => 4
        )

    [3] => Array
        (
            [product_tag] => worn
            [id] => 5
        )
)