Оптимизация группы за массивом во вложенную структуру для больших наборов данных - PullRequest
1 голос
/ 05 мая 2019

Дан «плоский» массив с полями (статус, тип и т. Д.), Которые могут быть динамическими (больше или меньше пар ключ / значение), например:

$data = array(
    array(
        "status" => "new",
        "type" => "type1",
        "source" => "source1",
        "other" => "other1",
        "count" => "1",
    ),
    ...

Цель состоит в том, чтобы получить многомерный / вложенный массив, «сгруппированный» по разному количеству группируемых полей. Например, если необходимо сгруппировать по 4 полям:

$groups = array("status", "type", "source", "other");

Если нет дочерних элементов, тогда ключ «data» должен содержать все «необработанные» данные, если есть дочерние, то групповое поле и значение, как в демонстрационном примере и на этом рисунке children/data

Результирующий набор данных должен быть следующим:

Array
(
    [0] => Array
        (
            [fieldName] => status
            [value] => new
            [children] => Array
                (
                    [0] => Array
                        (
                            [fieldName] => type
                            [value] => type1
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [fieldName] => source
                                            [value] => source1
                                            [children] => Array
                                                (
                                                    [0] => Array
                                                        (
                                                            [fieldName] => other
                                                            [value] => other1
                                                            [data] => Array
                                                                (
                                                                    [0] => Array
                                                                        (
                                                                            [status] => new
                                                                            [type] => type1
                                                                            [source] => source1
                                                                            [other] => other1
                                                                            [count] => 1
                                                                        )

Я адаптировал решение из ( реорганизации массива php во вложенный иерархический массив ), но оно довольно грязное и требует большого количества памяти и времени. Может ли он быть оптимизирован для больших наборов данных (10000 и более записей «плоского» массива), повышения производительности и улучшения кода?

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

Демо

1 Ответ

2 голосов
/ 05 мая 2019

Жаль, что вы не объясните, для чего это будет использоваться, но это общая проблема с вопросами переполнения стека. Суть проблемы часто отсутствует, поэтому она становится абстрактным упражнением.

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

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

function rearrangeItems($flatItems, $groups)
{
    $groupedItems = [];
    $groupName    = array_shift($groups);
    $groupValues  = array_unique(array_column($flatItems, $groupName));
    foreach ($groupValues as $groupValue) {
        $children = [];
        foreach ($flatItems as $flatItem) {
            if ($flatItem[$groupName] == $groupValue) {
                $children[] = $flatItem;
            }    
        }    
        if (count($groups) > 0) {
            $children = rearrange($children, $groups);
            $groupKey = "children";
        }
        else {
            $groupKey = "data";
        }
        $groupedItems[] = ["fieldName" => $groupName, 
                           "value"     => $groupValue,
                           $groupKey   => $children];
    }    
    return $groupedItems;
}

Да, это все, что нужно. Это приводит к тому же результату.

Эта функция рекурсивная , она выполняет один уровень группировки и затем передает результат на следующий уровень, пока не останется больше уровней. Комплексный бит:

array_unique(array_column($flatItems, $groupName))

Возвращает все различные значения на текущем уровне группировки.

Это не самый эффективный алгоритм, но он понятен. Если бы я попытался сделать его более эффективным, читаемость, вероятно, пострадала бы, и это никогда не было хорошо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...