Массив массивов в массив уникальных значений с помощью Reduce / Map

У меня есть массив массивов, который должен стать 1 массивом уникальных значений.

[1, 3, 2], [5, 2, 1, 4], [2, 1]

Я хочу использовать reduce / map для решения проблемы, но похоже, что это не работает. Я решил проблему уже с вложенными циклами for, например:

function uniteUnique(arr) {
  var args = Array.from(arguments);
  var arr = [];

  for (var i = 0; i < args.length; i++) {
    for (var j = 0; j < args[i].length; j++) {
      if (!arr.includes(args[i][j])) {
        arr.push(args[i][j]);
      }
    }
  }
  return arr;
} 

Теперь я попытался решить проблему с помощью reduce / map, но не получил правильного решения, например:

function uniteUnique(arr) {
  var args = Array.from(arguments);
  return args.reduce(
    (arr, a) => a.map(n => (!arr.includes(n) ? arr.push(n) : n)),
    []
  );
}
console.info(uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]));

Я также попытался решить с помощью reduce / map, используя старый синтаксис, например:

function uniteUnique(arr) {
  var args = Array.from(arguments);
  return args.reduce(function(arr, a) {
    return a.map(function(n) {
      if (!arr.includes(n)) {
        return arr.push(n);
      } else {
        return n;
      }
    });
  });
}

Я предполагаю, что я что-то не делаю правильно с операторами return в функциях обратного вызова. Любая помощь будет оценена, спасибо.

Поведение ключевого слова "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) для оценки ваших знаний,...
2
0
157
2

Ответы 2

Проблема в том, что:

 arr.includes(n)

arr - это массив массивов, включает в себя не работает. Вы также никогда не пропускаете arr вниз по цепочке сокращения.


Проще всего решить:

  [...new Set(array.reduce((a, b) => a.concat(b), []))]

Это просто сглаживает массив, создает набор для уникальности и распределяет его в массив. Или другое элегантное решение с использованием итераторов:

 function* flatten(arr) {
   for(const el of arr) {
      if (Array.isArray(el)) {
        yield* flatten(el);
      } else {
       yield el;
     }
   }
}

const result = [];

 for(const el of flatten(array))
   if (!result.includes(el)) result.push(el);

не могли бы вы добавить немного пояснений, ваше решение выглядит действительно красиво и коротко

Panos K 25.04.2018 16:09

На самом деле я думаю, что arr - это мой пустой массив, объявленный в начальном сокращении, тогда как args - это мой массив массивов.

jhazelton1 25.04.2018 16:22

@ jhazelton1 да ты прав. Вы запутали меня странным аргументом функции.

Jonas Wilms 25.04.2018 16:36

Вместо использования array#map используйте array#forEach и вставьте уникальный номер в аккумулятор.

function uniteUnique(arr) {
  var args = Array.from(arguments);
  return args.reduce((arr, a) => {
    a.forEach(n => (!arr.includes(n) ? arr.push(n) : n));
    return arr
  },[]);
}
console.info(uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]));

В качестве альтернативы вы можете array#concat весь массив, а затем с помощью Set получить уникальное значение.

const arr = [[1, 3, 2], [5, 2, 1, 4], [2, 1]],
      unique = [...new Set([].concat(...arr))];
console.info(unique);

Можете ли вы объяснить, почему здесь работает array # forEach вместо array # map?

jhazelton1 25.04.2018 16:11

Даже array#map работал бы, но array#map возвращал новое значение для каждой итерации, которая перезаписывала старый результат. Итак, что вам нужно, это аккумулятор и проверка вашего числа относительно этого аккумулятора. Итак, вместо того, чтобы возвращать результат array#map, вам нужно было вернуть значение аккумулятора.

Hassan Imam 25.04.2018 16:13

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