как эффективно разделить объект на несколько объектов внутри массива

#javascript #arrays

#javascript #массивы

Вопрос:

У меня есть образец массива bunch в виде

 let bunch = [{fruit: "apple" , quantity: 1},{fruit: "banana" , quantity: 3}]
  

Я пытаюсь разделить объект на его количество раз -> если fruit есть banana и quantity > 1 как:

 //newBunch --> [{fruit: "apple" , quantity: 1},{fruit: "banana" , quantity: 1},{fruit: "banana" , quantity: 1},{fruit: "banana" , quantity: 1}]
  

Я попытался использовать reduce как :

 let bunch = [{fruit: "apple" , quantity: 1},{fruit: "banana" , quantity: 3}]
let res = bunch.reduce((acc,curr)=>{
        if(curr.quantity > 1 amp;amp; curr.fruit==='banana'){  
      var arr = []
        for(let i=0; i < curr.quantity ; i  ){
      var fr = {}
        fr.fruit = 'banana';
      fr.quantity = 1;   
      arr.push(fr)
      }
      acc.push(...arr)
    }
    else{
     acc.push(curr)
    }  
    return acc
},[])

console.log(res)  

Я получаю ожидаемый ввод-вывод, используя приведенный выше фрагмент, но был бы эффективный способ сделать это (возможно, меньше кода), или вы бы просто предложили использовать текущее решение? пожалуйста, проведите меня по этому вопросу. TIA

Ответ №1:

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

 let bunch = [
  { fruit: 'apple', quantity: 1 },
  { fruit: 'banana', quantity: 3 },
];

const result = [];
bunch.forEach(obj => {
  for (let i = 1; i <= obj.quantity; i  ) {
    result.push({ ...obj, quantity: 1 });
  }
});

console.log(result);  

Комментарии:

1. и добавление a if для проверки fruit === 'banana'

2. Я не понимаю, что вы имеете в виду. Не могли бы вы уточнить, что вы пытаетесь сказать?

3. на самом деле я пытаюсь сделать это для фруктов banana , но решение будет разделено на все фрукты с количеством> 1, я понял, но для других ссылка..

Ответ №2:

Вы можете использовать flatMap и Array.prototype.fill

 let bunch = [{fruit: "apple" , quantity: 1},{fruit: "banana" , quantity: 3}]
let result = bunch.flatMap((fruit) => {
  return Array(fruit.quantity).fill({ ...fruit, quantity: 1})
})
  

Комментарии:

1. Не используйте .fill() метод для вставки объекта в массив, потому что в случае banana , будет один объект, который будет вставлен по трем индексам массива. Подробнее см.: MDN -Array.prototype.fill()

2. @Yousaf как это влияет, не могли бы вы объяснить

3. Объект с banana будет вставлен с тремя индексами, то есть 1, 2 и 3, но базовый объект будет только один. Поэтому, если вы измените объект со вторым индексом, эти изменения будут отражены и в объектах с индексами 2 и 3, потому что в памяти есть только один объект. Вы можете проверить проблему, изменив количество объекта по второму индексу, а затем проверить объекты по индексам 2 и 3

4. @Yousaf, хороший момент, зависит от того, как кто-то планирует использовать результирующий массив. Если повторяющиеся элементы необходимо изменить, этот подход может не сработать, поскольку повторяющиеся элементы являются ссылкой на один объект.

5. @Yousaf имеет смысл, еще раз спасибо 🙂 …. в моем случае объекты статичны, и, возможно, тогда я смогу использовать этот подход

Ответ №3:

Вы можете использовать Array.prototype.reduce() для обхода вашего исходного массива.

  • На каждой итерации вы просто подготавливаете разреженный массив определенного размера quantity , используя Array() конструктор
  • Используйте Array.prototype.fill() Array.prototype.map() комбинацию и для заполнения вышеуказанного массива объектами, имеющими свойство fruit , равное исходному объекту и свойству quantity , заданному 1 (этот подход более чистый, чем использование просто .fill() для элементов непримитивного типа данных, таких как объекты)
  • Используйте Array.prototype.push() синтаксис вместе с расширением, чтобы поместить все элементы результирующего массива в .reduce() накопитель

 const src = [{fruit: "apple" , quantity: 1},{fruit: "banana" , quantity: 3}],

      result = src.reduce((acc, {fruit, quantity}) => {
        acc.push(
          ...Array(quantity)
            .fill()
            .map(_ => ({
              fruit, 
              quantity: 1
            }))
        )
        return acc
     }, [])
        
console.log(result)  
 .as-console-wrapper{min-height:100%;}  

Комментарии:

1. уменьшите снова ах :)… спасибо @Yevgen … Один вопрос, _ это тот буфер, который содержит результат?

2. да, спасибо за примечание о совместимости …. Но мне немного сложнее понять этот ответ, было бы здорово с небольшим объяснением 🙂

3. абсолютно производительность выше …. спасибо и за объяснение :)… выбранный ответ был рассмотрен позже и изменен на другой, и он намного более удобочитаемый и простой…

Ответ №4:

Я предлагаю использовать Array.prototype.flatMap() и Array.from()

 let bunch = [
  { fruit: 'apple', quantity: 2 },
  { fruit: 'banana' , quantity: 3 }, 
  { fruit: 'starfruit', quantity: 1 },
];

const splitBunches = bunch.flatMap((fruit) => (
  Array.from({ length: fruit.quantity }, () => ({ ...fruit, quantity: 1 }))
))

console.log(splitBunches)