Массив дерева usort PHP

Я хочу отсортировать массив древовидной иерархии со структурой, как показано ниже, на основе ключа (в этом примере: отметка времени).

$topics = array(
  array('name' => 'n1', 'timestamp' => 5000, 'children' => array()),
  array('name' => 'n2', 'timestamp' => 4000, 'children' => array(
    array('name' => 'n3', 'timestamp' => 6000, 'children' => array()),
    array('name' => 'n4', 'timestamp' => 2000, 'children' => array(
      array('name' => 'n5', 'timestamp' => 4000, 'children' => array()),
      array('name' => 'n6', 'timestamp' => 3000, 'children' => array())
    )), 
  )),
  array('name' => 'n7', 'timestamp' => 1000, 'children' => array())
);

Моя функция сортировки:

function sequenceSort(&$a, &$b) {
  if (!empty($a['children'])) {
    usort($a['children'], 'sequenceSort');
  }
  if ($a['timestamp'] == $b['timestamp']) {
    return 0;
  }
  return $a['timestamp'] < $b['timestamp'] ? -1 : 1;
}

usort($topics, 'sequenceSort');
print_a($topics);

На некоторых уровнях он дает правильный результат, на другом - нет, например:

1000 ✔
4000 ✔
   6000 ✘
   2000 ✘
      4000 ✘
      3000 ✘
5000 ✔

Что в этом плохого?

Вы не можете изменить массив внутри usort

Coloured Panda 09.08.2018 09:22

@kaspars Для этого я использую передачу по ссылкам.

Justinus Hermawan 09.08.2018 09:25

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

jeroen 09.08.2018 09:28

@jeroen Я отредактировал вопрос с более случайным порядком ввода.

Justinus Hermawan 09.08.2018 09:32

@emix Должно быть <=> (single =), верно?

Justinus Hermawan 09.08.2018 09:38
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
5
178
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это не работает, потому что usort() не передает элементы массива по ссылке, даже если вы объявили параметры с помощью &. Я добавил:

$a['touched'] = true;

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

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

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

function sortRecurse(&$array) {
    usort($array, function($a, $b) {
        return $a['timestamp'] - $b['timestamp'];
    });
    foreach ($array as &$subarray) {
        sortRecurse($subarray['children']);
    }
}

ДЕМО

Я так и думал, но это тоже неправильно.

jeroen 09.08.2018 09:27

@JustinusHermawan Это не работает, потому что элементы не передаются по ссылке в функцию сравнения. Так что приведенный выше комментарий Каспара верен.

Barmar 09.08.2018 09:39

@barmar Да, работает. Итак, ошибка здесь в том, что функция usort() не извлекает параметры по ссылке, верно?

Justinus Hermawan 09.08.2018 09:54

Он получает свой собственный параметр по ссылке, но не передает параметры в функцию сравнения по ссылке.

Barmar 09.08.2018 09:55

так плохо, я опоздал sandbox.onlinephpfunctions.com/code/…

Sakezzz 09.08.2018 09:59

Не назначайте $topics[$i][]. recSort() модифицирует массив на месте, ничего не возвращает.

Barmar 09.08.2018 10:01

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