Wenhan Hou
Wenhan Hou

Reputation: 69

split array of objects in javascript into separate arrays based on a property

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?

Upvotes: 5

Views: 9215

Answers (5)

Mateusz Osuch
Mateusz Osuch

Reputation: 357

@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;
    }, []);
};

Upvotes: 0

haldagan
haldagan

Reputation: 911

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);

Upvotes: 0

TheChetan
TheChetan

Reputation: 4616

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"))

Upvotes: 1

Siva Kondapi Venkata
Siva Kondapi Venkata

Reputation: 11011

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));

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386868

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>');

Upvotes: 5

Related Questions