Reputation: 549
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.
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' } },
{} ]
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.
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
];
Upvotes: 0
Views: 102
Reputation: 10729
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), '@@')
Upvotes: 1
Reputation: 1248
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);
Upvotes: 0
Reputation: 7923
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)
Upvotes: 0