Разделить элементы массива объектов на группы по n в каждой javascript

#javascript

Вопрос:

У меня есть объект, как показано ниже:

 const boxOfFruits = {
  apples: [
    {
      name: "Kashmiri",
    },
    {
      name: "Washington",
    },
    {
      name: "Himalayan",
    },
    {
      name: "Fuji",
    }
  ],
  oranges: [
    {
      name: "Nagpur",
    },
    {
      name: "Clementine",
    },
  ],
mangoes: [
    {
      name: "Totapuri",
    },
    {
      name: "Alphonso",
    },
    {
      name: "Langda",
    },
  ],
}
 

Я хочу разделить эти фрукты на коробки; максимум n в каждой, скажем, где n равно 3, а яблоки, апельсины и манго распределены поровну.

Таким образом, результат в этом случае будет:

 box_1 = [{name: "Kashmiri"}, {name: "Nagpur"},{name: "Totapuri"}];
box_2 = [{name: "Washington"}, {name: "Clementine"},{name: "Alphonso"}];
box_3 = [{name: "Himalayan"},{name: "Langda"}, {name: "Fuji"}];
 

Тип фруктов (яблоко, апельсины и т. Д.) / ключей в объекте может увеличиваться / уменьшаться, и n также является переменной. В случае, если общее количество плодов меньше n, то это будет всего 1 коробка фруктов.

Что я пробовал до сих пор:

Используя Lodash, я вычисляю минимальные и максимальные плоды в одном типе:

 const minFruitType = _.min(Object.values(basket).map((eachBasket: any) => eachBasket.length));

 

Общее количество команд будет равно сумме плодов / n

Будет распределять минимальные фрукты (l) в первых l полях и заполнять остальные оставшимися фруктами на каждой итерации, в то время как в начале каждой итерации будет снова вычисляться минимальный тип фруктов.

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

1. звучит неплохо. Что вы придумали до сих пор?

2. Я добавлю то, что я сделал до сих пор в вопросе, мой плохой.

Ответ №1:

Вы можете использовать Object.values() , array#reduce и array#forEach для преобразования вашего объекта.

 const boxOfFruits = { apples: [ { name: "Kashmiri", }, { name: "Washington", }, { name: "Himalayan", }, ], oranges: [ { name: "Nagpur", }, { name: "Clementine", }, ], mangoes: [ { name: "Totapuri", }, { name: "Alphonso", }, { name: "Langda", }, ], },
    result = Object.values(boxOfFruits).reduce((r, arr) => {
      arr.forEach((o,i) => {
        const key =  `box_${i 1}`;
        r[key] ??= r[key] || [];
        r[key].push(o)
      });
      return r;
    },{});
console.log(result); 

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

1. Если я добавлю еще один фрукт в apple, приведенный выше код не будет работать, он создаст поле 3 с двумя фруктами и поле 4 с 1. В то время как в поле 3 должно быть 3 фрукта, что соответствует требованиям для каждого поля

Ответ №2:

Самым простым способом было бы использовать lodash.js zip() функция:

 const boxes = _.zip( Object.values(boxOfFruits) );
 

Обратите внимание, что _.zip() это даст вам неопределенные значения, когда исходные массивы имеют разную длину, поэтому вам нужно / нужно их отфильтровать:

 const boxes == _.zip( Object.values(boxOfFruits) )
               .map(
                 box => box.filter(
                   x => x !== undefined
                 )
               );
 

Но это не приведет к равномерному распределению плодов. Для этого не должно быть намного сложнее, чем это:

 function distribute(boxOfFruits, n) {

  const boxes = [];
  const fruits = Object.keys(boxOfFruits);
  
  for ( const fruit of fruits ) {

    let i = 0;
    const items = boxOfFruits[fruit];

    for (const item of items) {
      boxes[i] = !boxes[i] ?? [];
      boxes[i] = boxes[i].push(item);
        i;
      i = i < n ? i : 0 ;
    }

  }

  return boxes;
}
 

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

1. те же части в вашем ответе не работали для меня, обновили и поделились моим собственным ответом. Проверьте

Ответ №3:

Модифицированная версия ответа @Nicholas Carey сработала для меня:

 function distribute(boxOfFruits, n) {
  let boxes = [];

  let totalFruits = Object.values(boxOfFruits)
    .reduce((content, current) => content   current.length, 0);
  let maxBoxes = Math.ceil(totalFruits / 4);

  Object.values(boxOfFruits).forEach((fruits) => {
    let i = 0;
    fruits.forEach((fruit) => {
      boxes[i] ??= boxes[i] || [];
      boxes[i].push(fruit);
        i;
      i = i < (n 1) ? i : 0;
    });
  });

  // Extra boxes created, redistribute them to
  // starting boxes
  let newBoxes = teams.slice(0, maxBoxes);
  let pendingBoxes = teams.slice(maxBoxes);
  let pendingFruits = pendingBoxes.flat();

  let distributedBoxes = newBoxes.map((eachBox) => {
    let required = n - eachBox.length;
    if (required > 0) {
      eachBox.push(...pendingFruits.splice(0, required));
    }
    return eachBox;
  });

  return distributedBoxes;
}
 

Код практически такой же, как у Николаса, примите следующие изменения:

  1. Непосредственно извлекал значения и повторял их
  2. не удалось создать пустой массив, этот способ работает
  3. и проверьте максимальный размер поля с помощью n 1 вместо n