admin管理员组

文章数量:1287150

I know there's many ways to filter arrays for unique values, but what about filtering arrays for objects with unique values for a given field?

For example I have [obj1, obj2, obj3, ...] where each object is of the following form:

{
firstName: "...",
lastName: "..."
}

How can I filter the array to end up with a final array where all the objects have unique first names? A one-liner would be better, though not at the cost of readability.

I know there's many ways to filter arrays for unique values, but what about filtering arrays for objects with unique values for a given field?

For example I have [obj1, obj2, obj3, ...] where each object is of the following form:

{
firstName: "...",
lastName: "..."
}

How can I filter the array to end up with a final array where all the objects have unique first names? A one-liner would be better, though not at the cost of readability.

Share Improve this question asked Jul 16, 2017 at 3:52 frozenfrozen 2,13816 silver badges33 bronze badges 1
  • From torazaburo's answer, the 1-liner is : arr.filter((e, i) => arr.findIndex(e2 => e.firstName === e2.firstName) === i) – frozen Commented Jul 23, 2017 at 13:00
Add a ment  | 

6 Answers 6

Reset to default 9

Filter in only those items which are not found earlier in the array. We'll define cond as returning whether two items should be considered "equal".

function uniqueBy(a, cond) {
  return a.filter((e, i) => a.findIndex(e2 => cond(e, e2)) === i);
}

const test = [
  { firstname: "John", lastname: "Doe" },
  { firstname: "Jane", lastname: "Doe" },
  { firstname: "John", lastname: "Smith" }
];

console.log(uniqueBy(test, (o1, o2) => o1.firstname === o2.firstname));

You can reduce the array into a Map, and then spread the map values back to an array.

If you want to keep the 1st objects encountered, you have to check if the map already has the firstName as key, and set only if it doesn't exist yet.

const arr = [{"firstname":"Robert","lastname":"Smith"},{"firstname":"Francis","lastname":"Collins"},{"firstname":"Robert","lastname":"Ludlum"},{"firstname":"Francis","lastname":"bacon"}];
              
const result = [...arr.reduce((map, obj) => map.has(obj.firstname) ? map : map.set(obj.firstname, obj), new Map()).values()];

console.log(result);

If you want to keep the last objects, you can skip the check, and just set them:

const arr = [{"firstname":"Robert","lastname":"Smith"},{"firstname":"Francis","lastname":"Collins"},{"firstname":"Robert","lastname":"Ludlum"},{"firstname":"Francis","lastname":"bacon"}];

const result = [...arr.reduce((map, obj) => map.set(obj.firstname, obj), new Map()).values()];

console.log(result);

You can use reduce method, and set initial value to be an array, push object to the new array conditionally i.e. if first name doesn't already exist:

var arr = [ { firstname: "John",
              lastname: "Doe" },
            { firstname: "Jane",
              lastname: "Doe" },
            { firstname: "John",
              lastname: "Doe" }];
             

console.log(
  arr.reduce(
    function(unique_arr, obj) {
      if(!unique_arr.some(x => x.firstname === obj.firstname)) {
        unique_arr.push(obj)
      }
      return unique_arr; 
    }, [])
);

The answers seem intent on checking if your result array has the value, but for uniqueness I find it easier and more manageable to use an object and always set the value, without needing to check for it. This relies on the premise that objects may only have unique keys:

var arr = [{
    firstName: "Amy",
    lastName: "Adams"
  },
  {
    firstName: "Bryan",
    lastName: "Heart"
  },
  {
    firstName: "Amy",
    lastName: "Adams"
  }
];


var unique = {};

for (var i = 0, n = arr.length; i < n; i++) {
  // Key is your unique condition
  var key = [arr[i].firstName, arr[i].lastName].join(' ');
  unique[key] = arr[i];
}

console.log('Keys:', Object.keys(unique));     // only shown for austerity
console.log('Values:', Object.values(unique));

How about a 2-liner.

var ar = [{firstName: 'Jo'}, {firstName: 'Bill'}, {firstName: 'Bill'}];

var firstNames = [];
var uniqueFirstName = ar.filter(obj =>
  firstNames.indexOf(obj.firstName) > -1
      ? false : firstNames.push(obj.firstName))
console.log( JSON.stringify(uniqueFirstName));

I would filter and keep a Set of thr firstnames that already appeared:

 const names = new Set();

 const result = array.filter(({ firstName }) => !names.has(firstName) && names.add(firstName));

本文标签: javascriptFilter array for unique field valuesStack Overflow