0

Given an array of an even length:

const items = [
  'this/is/path1',
  'this/is/path2',
  'this/is/path3',
  'this/is/path4',
  'this/is/path5',
  'this/is/path6'
];

i want to create an array of objects that will have certain length objnb. Based on this length, i will divide the above items into chunks, and then store the first index on a new object property path, and the following elements in other1, other2; The same for the other object chunks.

My solution is hacky:

const objnb = 2;
const other1 = true;
const other2 = true;
const outputobjs = items.length / objnb;
const result = items.map((entry, index) => {
  let obj = {};
  console.log({ entry, index })
  if (index % outputobjs === 0) {
    obj.path = entry;
    obj.others = {};
    if (other1) {
      obj.others.two = items[index + 1];
    }
    if (other2) {
      obj.others.three = items[index + 2];
    }

    return obj;
  }

  return obj;
})


console.log('result: ', result)

the output is correct:

[ { path: 'this/is/path1',
    others: { two: 'this/is/path2', three: 'this/is/path3' } },
  {},
  {},
  { path: 'this/is/path4',
    others: { two: 'this/is/path5', three: 'this/is/path6' } },
  {},
  {} ]

but unfortunately, i get empty objects, which i don't want. How can i achieve the same with much cleaner way?

the preferred result will not contain the empty objects.

update

another example is:

const items = [
  'this/is/path1',
  'this/is/path2',
  'this/is/path3',
  'this/is/path4'
];

const objnb = 2;
const other1 = true;
const other2 = false;
const outputobjs = items.length / objnb;
const result = items.map((entry, index) => {
  let obj = {};
  console.log({ entry, index })
  if (index % outputobjs === 0) {
    obj.path = entry;
    obj.others = {};
    if (other1) {
      obj.others.two = items[index + 1];
    }
    if (other2) {
      obj.others.three = items[index + 2];
    }

    return obj;
  }

  return obj;
})


console.log('result: ', result)

and result is:

[ { path: 'this/is/path1', others: { two: 'this/is/path2' } },
  {},
  { path: 'this/is/path3', others: { two: 'this/is/path4' } },
  {} ]

clarification:

every object in the new array will be alike, for example, they will all have path, and since we are dividing the original array evenly, the new objects will have all the same properties. For example, if one has two, the rest of the objects in the new array will all have this property, and if they are supposed to have three, they all will have that property.

the new object will look like:

{ path: 'this/is/path1',
    others: { 
       two: 'this/is/path2', 
       three: 'this/is/path3' // optional; if one object has this, others must have it too.
    }
}

so basically, by dividing the original items array into a specific number, either 2, 3, 4, etc... we will chunk it into smaller arrays, and the new object path will be chunkedArray[0], and if there is one more item in this new chunked array, then two will be chunkedArray[1], and if still one more left, then three will be chunkedArray[2]

so if we divide it by 2, then we will have:

const chunkedArray1 = [
  'this/is/path1', // path
  'this/is/path2', //others.two
  'this/is/path3' //others.three
];

const chunkedArray2 = [
  'this/is/path4',// path
  'this/is/path5',//others.two
  'this/is/path6'//others.three
];

therefore the new objects will have two and three;

but if we divide it into 3, we will have:

const chunkedArray1 = [
  'this/is/path1',// path
  'this/is/path2'//others.two
];

const chunkedArray2 = [
  'this/is/path3',// path
  'this/is/path4'//others.two
];

const chunkedArray3 = [
  'this/is/path5',// path
  'this/is/path6'//others.two
];

so we will have only path and two for each object.

every new chunkedArray will have at least length of two, meaning that path and two is present in every new object.

another example:

and one basic example is, if the original array is three, then we can't divide it evenly to smaller chunks, so :

const items = [
  'this/is/path1', //path
  'this/is/path2',//others.two
  'this/is/path3'//others.three
];

and same here , if the original array is two length:

const items = [
  'this/is/path1', //path
  'this/is/path2',//others.two
];
4
  • does it have to be others.two, others.three... Or could it be others._2, others._3.. ? Commented Aug 6, 2018 at 21:00
  • @Logar actually i have a particular key name, that will be something like others[two] and const two = '2a', for example, and const three = '3a' Commented Aug 6, 2018 at 21:02
  • okay, my question was basically, can we use an 'index like' to generate the keys or do they have to be set manually ? Commented Aug 6, 2018 at 21:04
  • i have specific key names, and i have to use them Commented Aug 6, 2018 at 21:05

3 Answers 3

1

Below is one solution which uses reduce.

const items = [
  'this/is/path1',
  'this/is/path2',
  'this/is/path3',
  'this/is/path4',
  'this/is/path5',
  'this/is/path6'
]

function splitItems(data, chunkSize) {
  if (chunkSize < 2) return data // or the special value you'd like.
  const labels = {
    1: 'one',
    2: 'two',
    3: 'three',
    4: 'four'
    // ... others
  }
  return data.reduce((pre, cur, index) => {
    if (index % chunkSize === 0) {
      /* for old question
      pre.push({
        path: cur,
        others: {}
      })*/
      let newItem = {
        path: cur,
        others: {}
      }
      Array.from(Array(chunkSize-1).keys()).map( itemIndex => {
        newItem.others[labels[(itemIndex+1) % chunkSize + 1]] = '' //or other default valu
      })
      pre.push(newItem)
    }
    else {
      pre[pre.length - 1].others[labels[index % chunkSize + 1]] = items[index]
    }
    return pre
  }, [])
}

console.log('@Test Case 1@', splitItems(items, 2), '@@')
console.log('@Test Case 2@', splitItems(items.slice(0, 2), 2), '@@')
console.log('@Test Case 3@', splitItems(items.slice(0, 4), 2), '@@')
console.log('@Test Case 4@', splitItems(items.slice(0, 5), 3), '@@')

// calc the size first, then exec splitItems
function splitByLength(data, numberOfChunks) {
  let chunkSize = Math.round(data.length/3, 0)
  return splitItems(data, chunkSize)
}
console.log('@Test Case 5@', splitByLength(items.slice(0, 5), 3), '@@')

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

4 Comments

i think there is a bit of misunderstanding, i clarified it in the question
it is working as expected, but i would prefer the chunkSize you are passing in the argument to represent the number of objects in the new array.
i added another clarification if the original items is of length 2 or 3.
it is easy, just calcuate the chunkSize first, then execute function=splitItems, for your last question, just add one if statement to do the special process.
0

In short, you can loop every 3th item and push it as an object.

const items = [
  'this/is/path1',
  'this/is/path2',
  'this/is/path3',
  'this/is/path4',
  'this/is/path5',
  'this/is/path6'
];
var result = [];
for(var i = 0; i < items.length; i++){
    if(i%3==0){
      result.push({
          path: items[i],
          others: {two: items[i+1] || null, three: items[i+2] || null}
      })
    }
}

console.log(result)

2 Comments

this will only work for the given example. please see the other example i included in the post.
i think there is a bit of misunderstanding, i clarified it in the question
0

Another solution using reduce, a bit different from @sphinx answer, although quite similar :

const objnb = 3;
const otherKeys = ['two', 'three'];

const items = [
  'this/is/path1',
  'this/is/path2',
  'this/is/path3',
  'this/is/path4',
  'this/is/path5',
  'this/is/path6'
];

const outputobjs = Math.ceil(items.length / objnb);

const ar = items.reduce((memo, item, index) => {
  const mod = index % outputobjs
  if(mod === 0)
    memo.push({path: item, others: {}});
  else if(mod <= otherKeys.length)
    Object.assign(memo[memo.length - 1].others, {[otherKeys[mod -1]]: item});
  return memo;
}, []);

console.log(ar);

2 Comments

i think there is a bit of misunderstanding, i clarified it in the question
@storis not sure I got you right, The only worry you had with my answer was that you wanted to divide items into objnb different chunks and not into chunks of objnb length ? If so, I just reused your outputobjs and it works

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.