Sergey Topolov
Sergey Topolov

Reputation: 21

How to group data?

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

Answers (3)

Ori Drori
Ori Drori

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

Nina Scholz
Nina Scholz

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

HMR
HMR

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

Related Questions