Tengo un objeto de la siguiente manera:
const boxOfFruits = { apples: [ { name: "Kashmiri", }, { name: "Washington", }, { name: "Himalayan", }, { name: "Fuji", } ], oranges: [ { name: "Nagpur", }, { name: "Clementine", }, ], mangoes: [ { name: "Totapuri", }, { name: "Alphonso", }, { name: "Langda", }, ], }Quiero dividir estas frutas en cajas; máximo de n cada uno, digamos donde n es 3 y las manzanas, las naranjas y los mangos se distribuyen por igual.
Entonces la salida en este caso sería:
box_1 = [{name: "Kashmiri"}, {name: "Nagpur"},{name: "Totapuri"}]; box_2 = [{name: "Washington"}, {name: "Clementine"},{name: "Alphonso"}]; box_3 = [{name: "Himalayan"},{name: "Langda"}, {name: "Fuji"}];El tipo de frutas (manzana, naranjas, etc.)/claves en el objeto puede aumentar/disminuir y n también es variable. En caso de que el total de frutas sea menor que n, entonces sería solo 1 caja de frutas.
Lo que he probado hasta ahora:
Usando Lodash, estoy calculando las frutas mínimas y máximas en un solo tipo:
const minFruitType = _.min(Object.values(basket).map((eachBasket: any) => eachBasket.length));Total de equipos será la suma de los frutos/n
Distribuirá las frutas mínimas (l) en las primeras l cajas y llenará el resto con las frutas restantes en cada iteración, mientras que al comienzo de cada iteración calculará nuevamente el tipo mínimo de frutas.
Puede usar Object.values() , array#reduce y array#forEach para transformar su objeto.
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);La forma más fácil sería usar la función zip() de lodash.js :
const boxes = _.zip( Object.values(boxOfFruits) ); Tenga en cuenta que _.zip() le dará valores indefinidos cuando las matrices de origen tengan diferentes longitudes, por lo que necesitará/querrá filtrarlas:
const boxes == _.zip( Object.values(boxOfFruits) ) .map( box => box.filter( x => x !== undefined ) );Pero eso no distribuirá los frutos de manera uniforme. Para eso, no debería ser mucho más difícil que esto:
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; }Una versión modificada de la respuesta de @Nicholas Carey funcionó para mí:
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; }El código es más o menos el mismo que el de Nicholas, acepta los siguientes cambios: