Reputation: 21
How to write a script that groups the elements of an array into an array of arrays (or object of arrays), where the last is an array of elements grouped by sequence.
If next element Id is a part of sequence, it falls into prev group, else will be created new array and element will fall into it.
If element Id is higher than Id of prev element more than 1 - is is the same sequence = current array.
If element Id is higher than Id of prev element more than 2 - is is the next sequence = next (new) array.
If element neighbors Ids from all sides are both more than current Id - current element will create an array containing itself and it key will be its own Id.
Its no matter will be result is an array or an object - generating keys is easy, but group elements is hard to me now.
You can try writing in JavaScript, you can even use the Lodash library.
const data = [
{id: 1},
{id: 2},
{id: 3},
{id: 7},
{id: 9},
{id: 10},
{id: 12},
{id: 14},
{id: 15},
{id: 16}];
==========================================
const result = [
0/"1-4": [
{id: 1},
{id: 2},
{id: 3},
{id: 4}],
1/"7": [
{id: 7}],
2/"9-10": [
{id: 9},
{id: 10}],
3/"12": [
{id: 12}],
4/"14-16": [
{id: 14},
{id: 15},
{id: 16}]];
Upvotes: 0
Views: 55
Reputation: 192422
You can use chained Array.reduce()
calls to create the required structure:
const data = [{"id":1},{"id":2},{"id":3},{"id":7},{"id":9},{"id":10},{"id":12},{"id":14},{"id":15},{"id":16}];
const arrayOfGroups = data
.reduce((r, o, i) => {
// if first or not sequence add new sub array
if(!r.length || o.id !== data[i - 1].id + 1) r.push([]);
// push to last sub array
r[r.length - 1].push(o);
return r;
}, []);
const objectOfGroups = arrayOfGroups.reduce((r, a, i) => {
const start = a[0].id;
const end = a[a.length - 1].id;
// if start and end are equal, add just start (to main the order of insertion, start can be just a number)
const key = start === end ?
`${i}/${start}` : `${i}/${start}-${end}`;
r[key] = a;
return r;
}, {});
console.log('arrayOfGroups', arrayOfGroups);
console.log('objectOfGroups', objectOfGroups);
Upvotes: 0
Reputation: 386728
You could use a single loop approach by checking the last array of the result set and check the last object's id
if it is in wanted range.
If not, then add a new empty array to the result set. Later push the actual object to the last array.
var data = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 7 }, { id: 9 }, { id: 10 }, { id: 12 }, { id: 14 }, { id: 15 }, { id: 16 }],
grouped = data.reduce((r, o) => {
var last = r[r.length - 1];
if (!last || last[last.length - 1].id + 1 !== o.id) {
r.push(last = []);
}
last.push(o);
return r;
}, []);
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 0
Reputation: 39310
You could use reduce to create an array of arrays where the next expected number is current item id plus one.
const data = [
{id: 1},
{id: 2},
{id: 3},
{id: 7},
{id: 9},
{id: 10},
{id: 12},
{id: 14},
{id: 15},
{id: 16}]
.sort((a,b)=>a.id-b.id)//make sure it is sorted by id
.reduce(
([result,nextNum],item)=>{//nextNum is the next expected number
if(nextNum===undefined){//first time nextNum is undefined
nextNum=item.id;//set nextNum to id of current item
result.push([]);//add empty array
}
if(!(nextNum===item.id)){//current item id is not the expected next number
result.push([]);//add empty array
}
result[result.length-1].push(item);//add item to last array of the array of arrays
return [result,item.id+1];//next expected number is current item id + 1
},
[[],undefined]//initial values for result and nextNum
);
console.log(data)
Upvotes: 1