Как получить первый повторяющийся объект из массива объектов?

У меня есть массив таких объектов:

const result = [
  { ProductName: 'Orange', Origin: 'Italy' },
  { ProductName: 'Orange', Origin: 'Italy' },
  { ProductName: 'Lemon', Origin: 'Spain' },
  { ProductName: 'Avocado', Origin: 'Chile' }
];

// Expected output since there are duplicates:
const output = [{ ProductName: 'Orange', Origin: 'Italy' }]

Как показано выше, в массиве могут быть дубликаты (но это не обязательно). Вот почему я хотел бы:

  1. проверить, есть ли дубликаты в массиве
  2. если да: создайте новый массив только с дубликатами (покажите дубликаты только 1x, даже если в константном результате может быть 2 или 3 дубликата)
  3. если нет: оставить константный результат как есть

К настоящему времени я попытался изменить код, который делает обратное: он находит уникальные (не повторяющиеся) объекты в массиве результатов. Но я просто не могу заставить его работать. Может быть, это просто неправильный подход? Любая помощь приветствуется!

const endresult = result
  .map(e => e.ProductName)
  .map((e, i, final) => final.indexOf(e) === i && i)
  .filter(e => result[e])
  .map(e => result[e]);

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

Andreas 12.12.2020 12:29

Пожалуйста, покажите ожидаемый результат. Вы ожидаете out = [{ ProductName: 'Orange', Origin: 'Italy' }] или out = [{ ProductName: 'Orange', Origin: 'Italy' },{ ProductName: 'Lemon', Origin: 'Spain' },{ ProductName: 'Avocado', Origin: 'Chile' }]

pilchard 12.12.2020 12:39

@pilchard: ожидаемый результат: out = [{ ProductName: 'Orange', Origin: 'Italy' }]

Ewax_Du 12.12.2020 12:42
Поведение ключевого слова "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) для оценки ваших знаний,...
4
3
248
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

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

Вот решение с использованием уменьшить:

const result = [
  {ProductName: "Orange", Origin: "Italy"},
  {ProductName: "Orange", Origin: "Italy"},
  {ProductName: "Lemon",  Origin: "Spain"},
  {ProductName: "Avocado",Origin: "Chile"},
  {ProductName: "Orange", Origin: "Italy"}
];

function getDuplicatesOrAll(arr) {
  const duplicates = arr
    .reduce((acc, p, i) => {
      const isDuplicate = i !== result.findIndex(({ProductName}) => ProductName === p.ProductName);
      if (isDuplicate) {
        const wasAlreadyMet = acc.some(({ProductName}) => ProductName === p.ProductName);
        if (!wasAlreadyMet) {
          acc.push(p);
        }
      }
      return acc;
    }, []);
    
  return duplicates.length ? duplicates : arr;
}

console.info( getDuplicatesOrAll(result) );

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

 const result = [
  {ProductName: "Orange", Origin: "Italy"},
  {ProductName: "Orange", Origin: "Italy"},
  {ProductName: "Lemon",  Origin: "Spain"},
  {ProductName: "Avocado",Origin: "Chile"},
  {ProductName: "Orange", Origin: "Italy"}
];

function getDuplicatesOrAll(arr) {
  const duplicates = arr
    .map(({ProductName}) => ProductName)
    .reduce((acc, name, i, final) => {
      const isDuplicate = i !== final.indexOf(name);
      if (isDuplicate) {
        const wasAlreadyMet = acc.includes(name);
        if (!wasAlreadyMet) {
          acc.push(name);
        }
      }
      return acc;
    }, [])
    .map(name => result.find(({ProductName}) => ProductName === name));

  return duplicates.length ? duplicates : arr;
}

console.info( getDuplicatesOrAll(result) );

Итак, все работает, когда у меня есть дубликаты в массиве результатов. Но когда нет дубликатов, я получаю пустой массив. Я полагаю, нам нужно включить дополнительный оператор if-else? Что вы думаете?

Ewax_Du 12.12.2020 12:59

@Ewax_Du Я пропустил эту часть. Я отредактировал код и сделал функцию, содержащую эту логику.

blex 12.12.2020 13:07

Спасибо. Я проверил код, и он работает. Я отметил ваш ответ как решение, потому что вы дали мне 2 возможных фрагмента кода, и это облегчило мне - как новичку - следование. Еще раз спасибо!

Ewax_Du 12.12.2020 14:39

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

const result = [
  { ProductName: 'Orange', Origin: 'Italy' },
  { ProductName: 'Orange', Origin: 'Italy' },
  { ProductName: 'Lemon', Origin: 'Spain' },
  { ProductName: 'Avocado', Origin: 'Chile' }
];

function duplicateFinder(array){
  const cache = {};
  const duplicates = {};
  let endResult = [];
  array.forEach(e=>{
    cache[e.Origin]?
      duplicates[e.Origin] = e:
      cache[e.Origin] = true;
  })
  Object.keys(duplicates).forEach(e => {
      endResult.push(duplicates[e])
  })
  return endResult.length ? endResult : array;
}

console.info(duplicateFinder(result))

Можно выполнить с помощью Array#filter и Array#some.

  • Отфильтруйте массив, используя Array#filter, и для каждого объекта проверьте, повторяется ли этот объект.
  • Для объекта его повторение можно проверить с помощью Array#some.
  • Если найдены дубликаты, верните это, иначе верните исходный массив

const result = [
  { ProductName: 'Orange', Origin: 'Italy' },
  { ProductName: 'Orange', Origin: 'Italy' },
  { ProductName: 'Orange', Origin: 'Italy' },
  { ProductName: 'Orange', Origin: 'Italy' },
  { ProductName: 'Lemon', Origin: 'Spain' },
  { ProductName: 'Avocado', Origin: 'Chile' },
];

const getDups = (arr) => {
  const seen = new Set
  const dups = arr
    .filter((o1, i)=> arr.slice(i+1)
                          .some(o2 => o1.ProductName === o2.ProductName &&
                                      o1.Origin === o2.Origin)           
                       &&      
                      !arr.slice(0, i)
                         .some(o2 => o1.ProductName === o2.ProductName &&
                                      o1.Origin === o2.Origin));
  if (dups.length){
    return dups;
  }
  return arr;
}

console.info(getDups(result));

@blex спасибо, что заметили эту ошибку, исправил ее сейчас!

Fullstack Guy 12.12.2020 13:16

Вы можете сделать это, используя методы Array.prototype.sort() и Array.prototype.filter().

  • Сначала отсортируйте массив по ProductName.
  • Затем используйте метод фильтра для дубликатов.
  • Наконец, если дубликат не найден, верните исходный массив; в противном случае отфильтровывается повторяющийся результат.

const result = [
  { ProductName: 'Orange', Origin: 'Italy' },
  { ProductName: 'Orange', Origin: 'Italy' },
  { ProductName: 'Lemon', Origin: 'Spain' },
  { ProductName: 'Avocado', Origin: 'Chile' },
];
let ret = result
  .sort((x, y) => x.ProductName.localeCompare(y.ProductName))
  .filter((x, i, a) => i > 0 && x.ProductName === a[i - 1].ProductName);
if (!ret.length) ret = result;
console.info(ret);

const result=[{ProductName:"Orange",Origin:"Italy"},{ProductName:"Orange",Origin:"Italy"},{ProductName:"Lemon",Origin:"Spain"},{ProductName:"Avocado",Origin:"Chile"}];

const findDuplicates = (arr)  => { 
    let result =[]
    arr.forEach((e,i) => {
        let slice = arr.slice(i+1)
        let dupl = slice.find(n => (n.ProductName === e.ProductName) && (n.Origin === e.Origin))
        if (dupl){
             if (!result.find(n => (n.ProductName === dupl.ProductName) && (n.Origin === dupl.Origin))){
            result.push(dupl)
            }
        }    
    })
    return result
}

console.info(findDuplicates(result))

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