Leia_Organa
Leia_Organa

Reputation: 2094

JavaScript: Creating 2 dimensional array of objects based on condition

I'm working on a project that involves two dimensional arrays of objects. I've been working to try to figure out this answer for a while now, and I have some ideas of how to solve it, but I'm a bit stumped.

Let's assume there are animal shelters in City A and that each can hold 50 animals. Animals are coming in from different parts of the state, but the amount of animals from one place can never be more than 50. Here's an example of the animals coming in.

let animal_shelter_capacity =< 50;

let array 1 = [
  { "region": "NE", quantity: 25 },
  { "region": "NW", quantity: 21 },
  { "region": "SE", quantity: 43 },
  { "region": "SW", quantity: 18 },
  { "region": "Central", quantity: 20} 
]

In this example, the animals from NE (25) and NW (21) would go to one shelter (46 animals in total), the animals from SE (43) would go to another shelter (43 animals in total), and the animals from SW (18) and Central (20) would go to a third shelter (38 animals in total). The number of animals in one shelter can never be greater than 50.

So, I need to produce an array that looks like this:

let array2 = [ 
  [ { "region": "NE", quantity: 25 }, { "region": "NW", quantity: 21 }],
  [ { "region": "SE", quantity: 43 } ],
  [ { "region": "SW", quantity: 18 }, { "region": "Central", quantity: 20} ] 
]

I'm able to loop through array1 using forEach, but when it comes to adding until a certain value is reached, then creating a new array of arrays, I'm a little stumped on how to proceed to do this.

Here's what I have so far:

let array2 = [] //instantiate array

array1.forEach(function(element, index, array)
{
    let sum = 0;
    let capacity = 50;

    for (let j = 0; j < array1.length; j++)
    {
        sum += array1[j].quantity;
        if (sum >= capacity)
        {
            //create the new array consisting of the regions, push it into the larger array2
        }
    }
})

I'm not sure how to continue doing this. I know I need to do the following:

1. find a way to cut off the addition sequence once the quantity reaches 50
2. reset the sequence 
3. form the new arrays and push them into a larger array

Can anyone provide any advice on how to proceed?

Upvotes: 1

Views: 244

Answers (3)

Jon Grant
Jon Grant

Reputation: 49

Try this. Loop through shelters, if it can fit, add it to the current shelter list. If not, save the current shelter roster and start a new one. After the loop, make sure to save the current roster being written

const locations = [{
    "region": "NE",
    "quantity": 25
  },
  {
    "region": "NW",
    "quantity": 21
  },
  {
    "region": "SE",
    "quantity": 43
  },
  {
    "region": "SW",
    "quantity": 18
  },
  {
    "region": "Central",
    "quantity": 20
  }
]

const shelterRoster = [];
const capacity = 50;
let count = 0;
for (let location of locations) {
  let shelter = shelterRoster[shelterRoster.length - 1];

  if (!shelter || count + location.quantity > capacity) {
    shelterRoster.push([location]);
    count = 0;
  } else {
    shelter.push(location);
  }

  count += location.quantity
}

console.log(shelterRoster);

Upvotes: 1

mrReiha
mrReiha

Reputation: 955

The first point I've come up with, is you need to sort input data first. because your given input ( as asked in the question ) is not the only possible way of having data.

You can have some data like:

let array1 = [ 
{ "region": "NE", quantity: 25 },
{ "region": "NW", quantity: 21 },
{ "region": "Central", quantity: 20 },
{ "region": "SE", quantity: 43 },
{ "region": "SW", quantity: 18 },
]

and in this example, we should have pushed central and SW together, but not sorting the input at first place will result central and SW in different arrays.

So, conclusion. I think this is gonna work:

var make = function( arr ) {
    
        var res = [],
            currentArr = [];

        arr.forEach( v => {

            sum += v.quantity;

            if ( sum <= capacity ) {

                currentArr.push( v );

            } else {

                res.push( currentArr );
                currentArr = [ v ];
                sum = v.quantity;

            }

        });

        res.push( currentArr );

        return res;

    },

    array1 = [

        { "region": "NE", quantity: 25 },
        { "region": "NW", quantity: 21 },
        { "region": "Central", quantity: 20 },
        { "region": "SE", quantity: 43 },
        { "region": "SW", quantity: 18 }

    ],

    sum = 0,
    result,
    capacity = 50;

array1.sort( ( a, b ) => {

    return a.quantity - b.quantity;

});

console.log( array1 );

result = make( array1 );

console.log( result );

Upvotes: 0

Shidersz
Shidersz

Reputation: 17190

You can approach this with reduce(), using a custom object as the initial accumulator. When the reduce finish, you will need to do an extra line of code for get your final result.

const animal_shelter_capacity = 50;

const array1 = [ 
    {"region": "NE", quantity: 25},
    {"region": "NW", quantity: 21},
    {"region": "SE", quantity: 43},
    {"region": "SW", quantity: 18},
    {"region": "Central", quantity: 20} 
];

let obj = array1.reduce((res, curr) =>
{
    let test = (curr.quantity + res.c >= animal_shelter_capacity);

    return {
        r: test ? [...res.r, res.a] : res.r,
        c: test ? curr.quantity : res.c + curr.quantity,
        a: test ? [curr] : [...res.a, curr]
    };
},{r:[], c:0, a:[]});

let newArr = [...obj.r, obj.a];
console.log(newArr);

On the previous code, the accumulated object have the next keys:

  • r: The array of shelters generated progressively.
  • c: The counter of animals of the current shelter (see next).
  • a: The current shelter of animals.

When the reduce finish, the last shelter (that on the property a) will not be on the array of shelters. So, we have to put it manually (this is what the extra line does).

Upvotes: 0

Related Questions