5

I have an array like this:

var flightPlanCoordinates = [
  { lat: 37.772, lng: -122.214, status: "walking" },
  { lat: 36.772, lng: -123.214, status: "walking" },
  { lat: 21.291, lng: -157.821, status: "automotive" },
  { lat: -18.142, lng: 178.431, status: "automotive" },
  { lat: -27.467, lng: 153.027, status: "walking" },
  { lat: -26.467, lng: 151.027, status: "walking" },
];

and I want this to be split up into three arrays that have objects that have the same type like this following format:

[{lat: 37.772, lng: -122.214, status: 'walking'},
{lat: 36.772, lng: -123.214, status: 'walking'}]

[{lat: 21.291, lng: -157.821, status: 'automotive'},
{lat: -18.142, lng: 178.431, status: 'automotive'}]

[{lat: -27.467, lng: 153.027, status: 'walking'}
{lat: -26.467, lng: 151.027, status: 'walking'}]

I cannot just use groupBy to handle this, any ideas?

Siva K V
  • 10,561
  • 2
  • 16
  • 29
Wenhan Hou
  • 69
  • 1
  • 5

5 Answers5

5

You could use Array#reduce() with a group change if status is changing.

var flightPlanCoordinates = [{ lat: 37.772, lng: -122.214, status: 'walking' }, { lat: 36.772, lng: -123.214, status: 'walking' }, { lat: 21.291, lng: -157.821, status: 'automotive' }, { lat: -18.142, lng: 178.431, status: 'automotive' }, { lat: -27.467, lng: 153.027, status: 'walking' }, { lat: -26.467, lng: 151.027, status: 'walking' }],
    grouped = flightPlanCoordinates.reduce(function (r, a, i) {
        if (!i || r[r.length - 1][0].status !== a.status) {
            return r.concat([[a]]);
        }
        r[r.length - 1].push(a);
        return r;
    }, []);

document.write('<pre>' + JSON.stringify(grouped, 0, 4) + '</pre>');
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

Use for-loop, When the current element status is different from previous elements status, Then push the slice of array to output array.

const split = (arr) => {
  const output = [];
  let last = 0;
  for (let i = 1; i <= arr.length; i++) {
    if (arr[i]?.status !== arr[i - 1]?.status) {
      output.push(arr.slice(last, i));
      last = i;
    }
  }
  return output;
};

var flightPlanCoordinates = [
  { lat: 37.772, lng: -122.214, status: "walking" },
  { lat: 36.772, lng: -123.214, status: "walking" },
  { lat: 21.291, lng: -157.821, status: "automotive" },
  { lat: -18.142, lng: 178.431, status: "automotive" },
  { lat: -27.467, lng: 153.027, status: "walking" },
  { lat: -26.467, lng: 151.027, status: "walking" },
];

console.log(split(flightPlanCoordinates));
Siva K V
  • 10,561
  • 2
  • 16
  • 29
1

First we need to create a groupBy function as described in Nina's Answer. Then attach this function to the prototype of the array object so it becomes available globally like map and reduce. It can then be accessed using array.groupBy(key). The newly defined groupBy function will be available for all other arrays as well.

var flightPlanCoordinates = [
  { lat: 37.772, lng: -122.214, status: "walking" },
  { lat: 36.772, lng: -123.214, status: "walking" },
  { lat: 21.291, lng: -157.821, status: "automotive" },
  { lat: -18.142, lng: 178.431, status: "automotive" },
  { lat: -27.467, lng: 153.027, status: "walking" },
  { lat: -26.467, lng: 151.027, status: "walking" },
];


Array.prototype.groupBy = function(key) {
    return this.reduce(function (r, a, i) {
        if (!i || r[r.length - 1][0][key] !== a[key]) {
            return r.concat([[a]]);
        }
        r[r.length - 1].push(a);
        return r;
    }, []);
};

console.log(flightPlanCoordinates.groupBy("status"))
TheChetan
  • 4,440
  • 3
  • 32
  • 41
0

I would argue, that it's not question, just asking for code writing... Nonetheless

        Array.prototype.group_by_sequenced = function (field_name){
            var result = new Array();
            var j=0;
            for (var i=0;i<this.length;i++){
                var tmp = this[i];
                if (i==0) {
                    result[j]= new Array();
                } else if (this[i-1][field_name]!=this[i][field_name]) {
                    j++;
                    result[j] = new Array();
                }
                result[j].push(tmp);
            }
            return result;
        }
        
        var flightPlanCoordinates = [{ lat: 37.772, lng: -122.214, status: "walking" },{ lat: 36.772, lng: -123.214, status: "walking" },{ lat: 21.291, lng: -157.821, status: "automotive" }, { lat: -18.142, lng: 178.431, status: "automotive" },  { lat: -27.467, lng: 153.027, status: "walking" },  { lat: -26.467, lng: 151.027, status: "walking" }];
        var res = flightPlanCoordinates.group_by_sequenced('status');
        
        console.log(res);
haldagan
  • 911
  • 5
  • 16
0

@TheChetan's answer is far from ideal IMO it does not work well when the order of the elements in the initial array is not a happy order (unless it's a desired behavior but I doubt it).

Find below my proposal of solving it:

export const groupArrayByElementKey = (arr = [], key) => {
    if (!arr.some(el => key in el)) {
        return arr;
    }

    return arr.reduce((acc, curr) => {
        const existingGroupIndex = acc.findIndex(el => el[0][key] === curr[key]);

        if (!acc[existingGroupIndex]) {
            return acc.concat([[curr]]);
        } else {
            acc[existingGroupIndex].push(curr);
        }

        return acc;
    }, []);
};
Mateusz Osuch
  • 388
  • 1
  • 4
  • 14