JS - объединить массив массивов по первому элементу

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

[
    [
        "DL"
    ],
    [
        "DL",
        "ATL"
    ],
    [
        "MQ"
    ],
    [
        "MQ",
        "DFW"
    ],
    [
        "WN"
    ],
    [
        "WN",
        "MDW"
    ],
    [
        "EV"
    ],
    [
        "EV",
        "ATL"
    ],
    [
        "EV",
        "IAH"
    ],
    [
        "WN",
        "LAS"
    ],
    [
        "MQ",
        "ORD"
    ],
    [
        "WN",
        "BWI"
    ]
]

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

[
    [
        "DL"
    ],
    [
        "DL",
        "ATL"
    ],
    [
        "MQ"
    ],
    [
        "MQ",
        "DFW"
    ],
    [
        "MQ",
        "ORD"
    ],
    [
        "WN"
    ],
    [
        "WN",
        "MDW"
    ],
    [
        "WN",
        "LAS"
    ],
    [
        "WN",
        "BWI"
    ]
    [
        "EV"
    ],
    [
        "EV",
        "ATL"
    ],
    [
        "EV",
        "IAH"
    ],
]

обратите внимание, что последние три пункта переместились вверх:

    [
        "WN",
        "LAS"
    ],
    [
        "MQ",
        "ORD"
    ],
    [
        "WN",
        "BWI"
    ]

быть последними элементами ниже MQ и WN. БЕЗ потери заказа.

значение:

  • MQ/ORD был перемещен чуть ниже MQ/DFW.
  • WN/LAS и WN/BWI были перемещены чуть ниже WN/MDW без потери порядка.

Любое предложение для простого и элегантного способа сделать это?

БОНУС:

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

например

[
    [
        "WN",
        "BWI"
    ],
    [
        "MQ",
        "ORD"
    ],
    [
        "WN",
        "LAS"
    ],
    [
        "EV",
        "IAH"
    ],
    [
        "EV",
        "ATL"
    ],
    [
        "WN",
        "MDW"
    ],
    [
        "MQ",
        "DFW"
    ],
    [
        "US"
    ],
    [
        "US",
        "CLT"
    ],
    [
        "EV"
    ],
    [
        "MQ"
    ],
    [
        "AA"
    ],
    [
        "AA",
        "DFW"
    ],
    [
        "DL"
    ],
    [
        "DL",
        "ATL"
    ],
    [
        "WN"
    ]
]

Где опять же вложить его нужно таким же образом, не теряя порядка "ТОП" элементов (US должен быть выше EV) и всех элементов, вложенных ниже в том же порядке:

[
    [
        "US"
    ],
    [
        "US",
        "CLT"
    ],
    [
        "EV"
    ],
    [
        "EV",
        "IAH"
    ],
    [
        "EV",
        "ATL"
    ],
    [
        "MQ"
    ],
    [
        "MQ",
        "ORD"
    ],
    [
        "MQ",
        "DFW"
    ],
    [
        "AA"
    ],
    [
        "AA",
        "DFW"
    ],
    [
        "DL"
    ],
    [
        "DL",
        "ATL"
    ],
    [
        "WN"
    ],
    [
        "WN",
        "BWI"
    ],
    [
        "WN",
        "LAS"
    ],
    [
        "WN",
        "MDW"
    ],
]
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

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

// swapped the first 2 elements to handle a case of a child going before its parent

const arr = [["DL","ATL"], ["DL"],["MQ"],["MQ","DFW"],["WN"],["WN","MDW"],["EV"],["EV","ATL"],["EV","IAH"],["WN","LAS"],["MQ","ORD"],["WN","BWI"]];

const mapped = 
  arr.reduce((map, item) => {
    map[item[0]] ??= [];
    item.length > 1 && map[item[0]].push(item);
    return map;
}, {});

const result = Object.entries(mapped).reduce((result, [key, val]) => {
  result.push([key], ...val);
  return result; 
}, []);

console.info(JSON.stringify(result));

Более элегантным решением было бы использование sort(), но оно намного медленнее.

const arr = [["DL", "ATL"], ["DL"], ["MQ"], ["MQ", "DFW"], ["WN"], ["WN", "MDW"], ["EV"], ["EV", "ATL"], ["EV", "IAH"], ["WN", "LAS"], ["MQ", "ORD"], ["WN", "BWI"]];

arr.sort((a, b) => {
    
    // if items on the same level or have a different parent
    if (a.length === b.length || a[0] !== b[0]) {
        // sort by parent index
        return arr.findIndex(item => item[0] === a[0]) - 
          arr.findIndex(item => item[0] === b[0]);
    }

    return a.length - b.length;

});

console.info(JSON.stringify(arr));

И сравнение двух с массивом, увеличенным в 500 раз:

<script benchmark data-count = "1">

    const original = [["DL", "ATL"], ["DL"], ["MQ"], ["MQ", "DFW"], ["WN"], ["WN", "MDW"], ["EV"], ["EV", "ATL"], ["EV", "IAH"], ["WN", "LAS"], ["MQ", "ORD"], ["WN", "BWI"]];

    // increase the input array 500x
    const getData = () => Array.from({ length: 500 }, (_, idx) => original.map(item => {
        return item.map(name => `${name}${idx}`);
    }))
        .flat();

    // @benchmark mapped solution

    const arr = getData();

    // @run

    const mapped =
        arr.reduce((map, item) => {
            map[item[0]] ??= [];
            item.length > 1 && map[item[0]].push(item);
            return map;
        }, {});

    Object.entries(mapped).reduce((result, [key, val]) => {
        result.push([key], ...val);
        return result;
    }, []);


    // @benchmark sort solution

    const arr2 = getData();

    // @run

    arr2.sort((a, b) => {

        if (a.length === b.length || a[0] !== b[0]) {
            return arr2.findIndex(item => item[0] === a[0]) -
                arr2.findIndex(item => item[0] === b[0]);
        }

        return a.length - b.length;

    });

</script>
<script src = "https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js"></script>

Спасибо! Это не то решение, о котором меня просили :) — оно сортирует ВСЕ элементы в алфавитном порядке, но мне нужно сохранить порядок и размещать элементы только по первому элементу, как в моем примере.

ET-CS 14.06.2023 09:06
EV элементы должны оставаться последними
ET-CS 14.06.2023 09:07

@ET-CS понятно, готово

Alexander Nenashev 14.06.2023 09:24

Идеальный!! Спасибо!!

ET-CS 14.06.2023 09:26

Я бы хотел, чтобы это было более простое решение - но это потрясающе! работающий!

ET-CS 14.06.2023 09:26

@ET-CS я пытаюсь сделать это с sort(). я сообщу, если я приду к решению.

Alexander Nenashev 14.06.2023 09:27

Несколько плохих практик в этом коде. что es-lint не нравится. например, переназначение параметра внутри сокращения или for..in вместо Object.values()... ничего, что я не могу исправить :)

ET-CS 14.06.2023 09:31

@ET-CS я не вижу переназначения параметров, я бы хотел, чтобы у меня был ваш .eslintrc.js, исправление)

Alexander Nenashev 14.06.2023 09:34

@ET-CS, не могли бы вы дать мне правило переназначения параметров eslint?

Alexander Nenashev 14.06.2023 09:35

Это нормально. Я разберусь с вопросами estlint :)

ET-CS 14.06.2023 09:36

Примечание. Этот код предполагает, что одноэлементные массивы всегда будут первыми. Я обновил вопрос бонусной частью в обратном порядке. что является жизнеспособным условием, которое у меня есть в моем приложении. Если у кого-то есть хорошее решение, которое справится с обоими, это будет здорово :)

ET-CS 14.06.2023 09:37

@ET-CS проверьте это, сделал конкретный случай, когда ребенок идет раньше своего родителя

Alexander Nenashev 14.06.2023 09:43

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

ET-CS 14.06.2023 09:45

обратите внимание, что я добавил бонусную часть для обратной логики. есть идеи, как поддерживать оба пути в вашей логике?

ET-CS 14.06.2023 09:46

@ET-CS я уже реализовал бонусную часть, проверьте пожалуйста

Alexander Nenashev 14.06.2023 09:49

Ты восхитителен!

ET-CS 14.06.2023 09:51

Одно но :) у вас ошибка в коде. Посмотрите на свою консоль... в ней есть объекты вместо массивов для отдельных элементов (DL вместо ['DL'])

ET-CS 14.06.2023 09:55

@ET-CS да, исправляю, также у меня есть решение sort()!

Alexander Nenashev 14.06.2023 10:03
arr.sort((a, b) => a.length - b.length).filter(a => a.length === 1).flatMap(a => arr.filter(b => b[0] === a[0]))
Thomas 14.06.2023 10:12

@Thomas не справляется с ребенком, идущим раньше своего родителя

Alexander Nenashev 14.06.2023 10:21

@AlexanderNenashev да, для этого и нужен sort().

Thomas 14.06.2023 10:22

Удивительный! Итак, я вижу, что сортировка менее эффективна, чем карта!

ET-CS 14.06.2023 10:23

@Thomas ой, я ошибся, это вообще не работает: [["DL"],["MQ"],["WN"],["EV"],["DL","ATL"] ,["MQ","DFW"],["WN"‌​,"MDW"],["EV","ATL"]‌​,["EV","IAH"],["WN", ‌​"LAS"],["MQ","ORD"],‌​["WN","BWI"]]

Alexander Nenashev 14.06.2023 10:26

@ET-CS обновил бенчмарк и кажется, что сортировка НАМНОГО медленнее...

Alexander Nenashev 14.06.2023 12:43

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