Group values in array by two properties JavaScript

We have an array of objects like this:

const arr = [
    { value: 12, gap: 1 },
    { value: 13, gap: 1 },
    { value: 14, gap: 1 },
    { value: 15, gap: 1 },
    { value: 19, gap: 2 },
    { value: 21, gap: 1 },
    { value: 22, gap: 1 },
    { value: 23, gap: 1 },
    { value: 27, gap: 1 },
    { value: 31, gap: 4 },
    { value: 35, gap: 4 },
    { value: 39, gap: 4 },
    { value: 43, gap: 1 },
    { value: 50, gap: 1 },
    { value: 51, gap: 1 },
    { value: 52, gap: 1 },
    { value: 55, gap: 1 },
    { value: 57, gap: 1 },
];

We need to write a function that groups consecutive objects where each object's value equals the sum of the previous object's value and gap. Objects that follow this pattern should be grouped together in subarrays.

For example, the object with value 12 has gap 1, and the next object has value 13 (12 + 1 = 13), so they must be grouped together along with objects having values 14 and 15.

Understanding the Logic

The grouping rule is: if current.value === previous.value + previous.gap, then the current object belongs to the same group as the previous one. Otherwise, start a new group.

12 (gap:1) 13 (gap:1) 14 (gap:1) 12+1=13 13+1=14 19 (gap:2) Break: 15+1?19 Group 1 Group 2

Solution Using Array.reduce()

We'll use Array.prototype.reduce() to construct the grouped array by tracking the current group and checking the continuity condition:

const arr = [
    { value: 12, gap: 1 },
    { value: 13, gap: 1 },
    { value: 14, gap: 1 },
    { value: 15, gap: 1 },
    { value: 19, gap: 2 },
    { value: 21, gap: 1 },
    { value: 22, gap: 1 },
    { value: 23, gap: 1 },
    { value: 27, gap: 1 },
    { value: 31, gap: 4 },
    { value: 35, gap: 4 },
    { value: 39, gap: 4 },
    { value: 43, gap: 1 },
    { value: 50, gap: 1 },
    { value: 51, gap: 1 },
    { value: 52, gap: 1 },
    { value: 55, gap: 1 },
    { value: 57, gap: 1 },
];

const groupArray = arr => {
    return arr.reduce((acc, val, ind, array) => {
        // the accumulated data and currentIndex of accumulated data
        const { data, currentIndex } = acc;
        // the current object properties
        const { value, gap } = val;
        // the previous object properties
        const v = arr[ind-1]?.value;
        const g = arr[ind-1]?.gap;
        
        if(ind === 0 || value !== v + g){
            // recording the index of last object and pushing new subarray
            const index = data.push([val]) - 1;
            return { data, currentIndex: index };
        };
        
        data[currentIndex].push(val);
        return { data, currentIndex };
    }, {
        data: [],
        currentIndex: 0
    }).data;
}

console.log(JSON.stringify(groupArray(arr), null, 2));
[
  [
    { "value": 12, "gap": 1 },
    { "value": 13, "gap": 1 },
    { "value": 14, "gap": 1 },
    { "value": 15, "gap": 1 }
  ],
  [
    { "value": 19, "gap": 2 },
    { "value": 21, "gap": 1 },
    { "value": 22, "gap": 1 },
    { "value": 23, "gap": 1 }
  ],
  [
    { "value": 27, "gap": 1 }
  ],
  [
    { "value": 31, "gap": 4 },
    { "value": 35, "gap": 4 },
    { "value": 39, "gap": 4 },
    { "value": 43, "gap": 1 }
  ],
  [
    { "value": 50, "gap": 1 },
    { "value": 51, "gap": 1 },
    { "value": 52, "gap": 1 }
  ],
  [
    { "value": 55, "gap": 1 }
  ],
  [
    { "value": 57, "gap": 1 }
  ]
]

How It Works

The function uses an accumulator object with two properties:

  • data: Array of grouped subarrays
  • currentIndex: Index of the current group being built

For each object, it checks if current.value === previous.value + previous.gap. If true, it adds the object to the current group. If false, it starts a new group.

Alternative Approach Using forEach

const groupArraySimple = arr => {
    const result = [];
    let currentGroup = [];
    
    arr.forEach((obj, index) => {
        if (index === 0) {
            currentGroup = [obj];
        } else {
            const prevObj = arr[index - 1];
            if (obj.value === prevObj.value + prevObj.gap) {
                currentGroup.push(obj);
            } else {
                result.push(currentGroup);
                currentGroup = [obj];
            }
        }
    });
    
    if (currentGroup.length > 0) {
        result.push(currentGroup);
    }
    
    return result;
};

console.log(JSON.stringify(groupArraySimple(arr), null, 2));

Conclusion

Both approaches successfully group consecutive objects based on the value-gap relationship. The reduce() method provides a functional programming approach, while the forEach() method offers a more straightforward imperative solution. Choose the approach that best fits your coding style and team preferences.

Updated on: 2026-03-15T23:18:59+05:30

1K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements