PHP Сортировка массива по алфавиту, за исключением ОДНОГО значения сверху, для выпадающего меню

Я пытаюсь взломать раскрывающееся меню, извлекающее информацию из множества стран, чтобы вверху отображалось "Соединенные Штаты" (id 1), а все остальные страны сортировались в алфавитном порядке. Как мне отсортировать все, кроме США, чтобы остаться на вершине, используя функцию usort для массива? Любые альтернативные предложения также приветствуются. Вот код:

while (list($key, $value) = each($countries->countries)) {
   $countries_array[] = array('id' => $key, 'text' => $value['countryname']);
}
function text_cmp($a, $b) {
   return strcmp($a["text"], $b["text"]);
} 
usort($countries_array, 'text_cmp'); 

5 ответов

Вообще говоря, вы можете повторно ввести свой массив, затем отсортировать по ключам, затем объединить массив с измененным ключом с массивом с одинокой строкой US, а затем повторно проиндексировать массив. Однако я не рекомендую его, потому что количество итераций, необходимых в процессе, непривлекательно велико. Другими словами, временная сложность неоптимальна.

      $keyed = array_column($countries, null, 'text');
ksort($keyed);
var_export(array_values(['United States' => $keyed['United States']] + $keyed));

Вы также можете позвонитьarray_search()сarray_column()изолируя значения, но в любом случае потребуется отсортировать столбец по алфавиту. Итак, опять же, я бы исключил это из соображений эффективности. Я бы также не рекомендовал какой-либо подход с использованиемin_array().


Правда в том, что эту задачу можно выполнить с помощью одногоusort()вызов.

Код: (Демо)

      usort(
    $countries,
    fn($a, $b) =>
        [$a['text'] !== 'United States', $a['text']]
        <=>
        [$b['text'] !== 'United States', $b['text']]
);
var_export($countries);

Предоставляя$aданные слева от оператора космического корабля и$bданные справа, сортировка ASC отключена.

Сортировка по возрастанию логических значений ставитfalseдоtrue. Чтобы убедиться, что строка US всегда имеет более высокий приоритет, чем любая другая строка, проверьте, является ли значение НЕ .

Первый элемент с каждой стороны оператора космического корабля — это первое правило. Когда обаtextзначения неUnited States, то применяется стандартная алфавитная сортировка.

Это очень эффективный подход, поскольку нет повторных вызовов функций.


Наконец, поскольку вы создаете новую, определенную структуру массива изcountriesсобственность вашего$countriesобъект внутри цикла, вы могли бы лучше использовать этот цикл. Может быть, что-то вроде этого:

      $result = [];
foreach ($countries->countries as $id => ['countryname' => $text]) {
    $row = compact(['id' 'text']);
    if ($text === 'United States') {
        $result[] = $row;
    } else {
        $theRest[] = $row;
        $texts[] = $text;
    }
}
array_multisort($texts, $theRest);
array_push($result, ...$theRest);
var_export($result);

Самый простой способ сделать это - удалить одно значение, отсортировать, а затем снова добавить его:

рабочий пример

// your countries array goes here:
$countries = array(2=>"Burma", 4=>"Zimbabwe", 10=>"France", 1=>"United States", 13=>"Russia");

$AmericaFKYeah = array(1=>"United States");
$countries =array_diff($countries, $AmericaFKYeah);
asort($countries);

// using + instead of array_unshift() preserves numerical keys!
$countries= $AmericaFKYeah + $countries;

дает тебе:

array(5) {
  [1]=>
  string(13) "United States"
  [2]=>
  string(5) "Burma"
  [10]=>
  string(6) "France"
  [13]=>
  string(6) "Russia"
  [4]=>
  string(8) "Zimbabwe"
}

С индексированным массивом

меры

  1. Найти ресурс в массиве
  2. Unset переменная в массиве
  3. Добавить ресурс в качестве первого элемента в массиве с помощью array_unshift (array_unshift - добавить один или несколько элементов к началу массива - http://php.net/manual/en/function.array-unshift.php)

Код

 if (in_array('yourResource', $a_array)){
    unset($a_array[array_search('yourResource',$a_array)]);
    array_unshift($a_array, 'yourResource');
 }

С многомерными массивами

$yourResorceToFind = 'yourResource';
foreach ($a_arrays as $a_sub_array){
  if (in_array($yourResorceToFind, $a_sub_array)){

    unset($a_arrays[array_search($yourResorceToFind,$a_sub_array)]);
    array_unshift($a_arrays, $a_sub_array);
    break;
  }
}

Попробуй это:

   <?php
   $array = array('Alpha', 'atomic', 'Beta', 'bank');
   $array_lowercase = array_map('strtolower', $array);
   array_multisort($array_lowercase, SORT_ASC, SORT_STRING, $array);
   print_r($array);
 ?>

выход:

Array

([0] => Alpha [1] => atomic [2] => bank [3] => Beta)

или же:

 $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')
 );

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

Я обнаружил, что эта тема пытается сделать то же самое уродливым способом, но поскольку моя техника кажется более простой, я делюсь ею, если кому-то нужно.

Самый простой способ сделать это - повозиться с результатом обратного вызова usort. Вам просто нужно сначала передать желаемое значение в обратном вызове следующим образом:

$countries = [
 ['id' => 2, 'text' => 'Burma'],
 ['id' => 4, 'text' => 'Zimbabwe'],
 ['id' => 10, 'text' => 'France'],
 ['id' => 1, 'text' => 'United States'],
 ['id' => 13, 'text' => 'Russia'],
];

$myFirstItem = "United States";

usort($countries, function($a, $b) use ($myFirstItem) {
    return $myFirstItem == $a['text'] ? -1 : ($myFirstItem == $b['text'] ? 1 : strcmp($a['text'], $b['text']));
});

Это некрасиво, но выполняет свою работу без необходимости играть с другими массивами, и все, как и ожидалось, выполняется в обратном вызове.

Другие вопросы по тегам