0

I'm looking to accomplish something similar to the _.chunk() function in lodash. The chunk function breaks an array into equal parts, based on the quantity of objects in the original array.

However, I want to break a Javascript array into smaller arrays based on the quantity of the object's subitems. So the new arrays can have a varying number of elements, but the quantity of subitems in each new array must total 3(except for the last array if there is a remainder).

For example, I want to use Javascript to convert this array:

[ {name:'John', numberOfPets: 5, 
pets:['petOne', 'petTwo', 'petThree', 'petFour', 'petFive']}, 
{ name:'Andrew', numberOfPets: 5,
pets: ['petSix', 'petSeven', 'petEight', 'petNine', 'petTen']}]

Into these arrays:

[{name: 'John', numberOfPets: 5, pets: ['petOne', 'petTwo', 'petThree']}],

[{name: 'John', numberOfPets: 5, pets: ['petFour', 'petFive']},
{name: 'Andrew', numberOfPets: 5, pets: ['petSix']}],

[{name: 'Andrew', numberOfPets: 5, pets: ['petSeven', 'petEight', 
'petNine']}],

[{name: 'Andrew', numberOfPets: 5, pets: ['petTen']}]

You will notice the new arrays each have 3 pets, except for the last array which just has 1 remainder.

Any help would be greatly appreciated.

3
  • 2
    What is pets? Array or object? It cant be both... Commented Feb 16, 2018 at 17:08
  • Yeah the pets property of each object is invalid as posted above. Commented Feb 16, 2018 at 17:14
  • Ah, you are right. Pets is an array, I've updated the syntax. I will try out your code now. Commented Feb 16, 2018 at 17:20

3 Answers 3

1

I think this is on the right track to what BeccaGirl is looking for. It may need some re-factoring.

var chunks = function(array, size) {
  var results = [];
  while (array.length) {
    results.push(array.splice(0, size));
  }
  return results;
};

var chunkSize = 3, newArray = [], chunkPets = [];
var oldArray = [ {name:'John', numberOfPets: 5, 
pets:['petOne', 'petTwo', 'petThree', 'petFour', 'petFive']}, 
{ name:'Andrew', numberOfPets: 5,
pets: ['petSix', 'petSeven', 'petEight', 'petNine', 'petTen']}];
var newArray = [];

for(var i=0; i<oldArray.length; i++){
  chunkPets = chunks(oldArray[i].pets, chunkSize);
  for(var j=0; j<chunkPets.length; j++)
  {
    if(chunkPets[j].length === chunkSize || i+1 === oldArray.length)
    {
   newArray.push([{name: oldArray[i].name, numberOfPets: oldArray[i].numberOfPets, pets: chunkPets[j]}]);
    }
    else{
       var tempArray = [];
       tempArray.push({name: oldArray[i].name, numberOfPets: oldArray[i].numberOfPets, pets: chunkPets[j]});
       
       if(oldArray.length > i+1){
       tempArray.push({name: oldArray[i+1].name, numberOfPets: oldArray[i+1].numberOfPets, pets: oldArray[i+1].pets.splice(0,chunkSize - chunkPets[j].length)});
       
       oldArray[i+1].pets = oldArray[i+1].pets.splice(chunkSize -chunkPets[j].length-1,oldArray[i+1].pets.length);
       newArray.push(tempArray);
       }
    }
  }
}

console.log(newArray);

Sign up to request clarification or add additional context in comments.

1 Comment

Yes, this is what I was looking for. Thank you!
1
 const result = [], size = 3;

 for(const {name, pets} of owners)
   for(let chunk = 0; chunk < pets.length; chunk += size)
       result.push({name, pets: pets.slice(chunk, chunk + size)});

Just chunk that for every person. I assume that your array is called owners (thought it would fit) and that owner.pets is an array (cause that would make sense too). Also note that your numberOfPets is unneccessary, as you can use pets.length;)

1 Comment

Each object has the original numberOfPets, so it is necessary in the output chunked array, although it can be derived from the length of the original one.
1

Assuming that pets in each input object is actually an array (which means it should be delimited by [...], not {...}), you can achieve the desired results with something like this:

const input = [{
        name: 'John',
        numberOfPets: 5,
        pets: [
            'petOne',
            'petTwo',
            'petThree',
            'petFour',
            'petFive'
        ]
    },
    {
        name: 'Andrew',
        numberOfPets: 5,
        pets: [
            'petSix',
            'petSeven',
            'petEight',
            'petNine',
            'petTen'
        ]
    }
]

const chunked = input.reduce(␣
  function(output, item) {
     const master = {...item}
     while (master.pets.length > 0) {
        const copy = {...master}
        copy.pets = master.pets.slice(0,3)
        master.pets = master.pets.slice(3)
        output.push(copy)
    }
    return output
 }, [])

console.log(chunked)

That results in chunked being this:

[ { name: 'John',
    numberOfPets: 5,
    pets: [ 'petOne', 'petTwo', 'petThree' ] },
  { name: 'John', numberOfPets: 5, pets: [ 'petFour', 'petFive' ] },
  { name: 'Andrew',
    numberOfPets: 5,
    pets: [ 'petSix', 'petSeven', 'petEight' ] },
  { name: 'Andrew',
    numberOfPets: 5,
    pets: [ 'petNine', 'petTen' ] } ]

3 Comments

I don't think the output is quite right yet, as I would need it to return an array of arrays, and each array should ultimately have 3 pets. So since there are 10 pets total, the arrays would have 3 pets, 3 pets, 3 pets and the last array would have 1 pet.
How are you going to combine two of John's pets and one of Andrew's into a single object?
It would be an array that contains 2 objects, one of John's pets and one of Andrew's pets: [{name: 'John', numberOfPets: 5, pets: ['petFour', 'petFive']}, {name: 'Andrew', numberOfPets: 5, pets: ['petSix]}]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.