PremKumar
PremKumar

Reputation: 1354

Get unique values from an array of objects

[
  {key1 : 'sometext'},
  {key2 : 'sometext'},
  {key1 : 'sometext'},
  {key3 : 'sometext'},
]

From the above code I need to get the results as follows, removing objects that contains same keys

[
  {key1 : 'sometext'},
  {key2 : 'sometext'},
  {key3 : 'sometext'},
]

Thanks in advance.

Upvotes: 1

Views: 179

Answers (4)

Koushik Chatterjee
Koushik Chatterjee

Reputation: 4175

_.uniqBy(data, _.findKey);

Explanation:

In _.uniqueBy() you need to tell on what value you want to derive the uniqueness, either you pass a string as attribute (the value of that attribute will be used in to determine uniqueness), or you pass a callback which will return a value and that value will be considered to evaluate uniqueness. In case the value upon which we will determine the uniqueness is a plain and native value, _.uniqueBy() is a better choice, so you don't need to compare manually (which you have to do if your value is a complex object and upon many keys the uniqueness is determined). In our case it is simple object key, which can be either string or symbol, So, the caparison part we can let on lodash with _uniqueBy

In our case, if we can return the only key (it must be exactly 1, otherwise none of the logic will work) of each object, _.uniqueBy() can do the further, so basically our aim is to pass a callback which will return the only key. we can simply pass a callback to evaluate that like: e => _.keys(e)[0]

Now, _.findkey takes object as first argument and truthy-ness of the returned value, if it's a truthy then it will return that key (unlike return that entity like _.find), so if you don't pass the callback, a default callback valued a => a is automatically assigned to handle that case. which means it will check the truthy ness of each entity (key in this case), and obviously, key have to be a truthy value, so it will return the first entity itself (first key here for _.findKey), hence passing a callback wrapping findKey with only one argument like a => _.findKey(a) is equivalent to pass _.findKey callback, we can make it more simple and _.uniqueBy(data, _.findKey) will do the job.

Let's have a snippet:

let data=[{key1:"sometext"},{key2:"sometext"},{key1:"sometext"},{key3:"sometext"}];

let res = _.uniqBy(data, _.findKey);

console.log('Unique Result: ', res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

Upvotes: 2

Ori Drori
Ori Drori

Reputation: 191976

With lodash you can use _.uniqBy(), and return the single key of each object:

const arr = [{"key1":"sometext"},{"key2":"sometext"},{"key1":"sometext"},{"key3":"sometext"}]

const result = _.uniqBy(arr, o => _.keys(o)[0])

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

Using vanilla JS, if you don't care if the 2nd item (the duplicate would be used, you can combine all items to a single object (this will remove the 1st duplicate), get the entries, and map back to an array of objects:

const arr = [{"key1":"sometext"},{"key2":"sometext"},{"key1":"sometext"},{"key3":"sometext"}]

const result = Object.entries(Object.assign({}, ...arr))
  .map(([k, v]) => ({ [k]: v }))

console.log(result)

Upvotes: 3

xdeepakv
xdeepakv

Reputation: 8125

Simple and fast solution. Not much iteration.

const data = [
  { key1: "sometext" },
  { key2: "sometext" },
  { key1: "sometext" },
  { key3: "sometext" }
];
const uniqueElementsBy = (arr, fn) =>
  arr.reduce((acc, v) => {
    if (!acc.some(x => fn(v, x))) acc.push(v);
    return acc;
  }, []);

const isEqual = (x, y) => JSON.stringify(x) == JSON.stringify(y);
console.log(uniqueElementsBy(data, isEqual));

// For complex solution

const isEqual2 = (x, y) => {
  const keys1 = Object.keys(x);
  const keys2 = Object.keys(y);

  if (keys1.length != keys2.length) return false;
  return !keys1.some(key => x[key] != y[key]);
};
console.log(uniqueElementsBy(data, isEqual2));
const data2 = [
  { key2: "sometext", key1: "sometext" },
  { key2: "sometext" },
  { key1: "sometext", key2: "sometext" },
  { key3: "sometext" }
];
console.log(uniqueElementsBy(data2, isEqual2));

const data3 = [
  { key1: "sometext" },
  { key2: "sometext" },
  { key1: "sometext", key2: "sometext" },
  { key3: "sometext" }
];
console.log(uniqueElementsBy(data3, isEqual2));
.as-console-row {color: blue!important}

Upvotes: 0

Reza
Reza

Reputation: 19843

This is using pure javascript, not using loadash

const arr = [
  {key1 : 'sometext'},
  {key2 : 'sometext'},
  {key1 : 'sometext'},
  {key3 : 'sometext'},
];

const result = arr.reduce((acc, item) => {

   if (!acc.find(x => Object.keys(x).sort().toString() == Object.keys(item).sort().toString() )) {
      acc.push(item)
   }
   
   return acc;
}, []);

console.log(result);

Upvotes: 1

Related Questions