What is the easiest way to get required keys from array of objects

Viewed 103

I required to extract unique keys from array, leaving unwanted keys. here is my try it works fine. But looking for the easiest way.

Live demo

const data = [{
  "year": "2021",
  "europe": 5,
  "namerica": 2.5,
  "asia": 1
}, {
  "year": "2022",
  "europe": 2.6,
  "namerica": 6.7,
  "asia": 2.2
}, {
  "year": "2023",
  "europe": 4.8,
  "namerica": 1.9,
  "asia": 4.4
}];

const uniqueLables = [];
const omit = ["year"]

for (let i = 0; i < data.length; i++) {
  for (const [key, value] of Object.entries(data[i])) {
    if (!uniqueLables.includes(key)) {
      if (!omit.includes(key)) {
        uniqueLables.push(key);
      }
    }
  }
}

console.log(uniqueLables) // => ['europe', 'namerica', 'asia']

8 Answers

If you don't need your omit keys to be dynamic (ie: in an array), you can merge every object together (using Object.assign()) to get an object with all keys, and then extract an object excluding year using destructuring assignment and take the keys of that:

const data = [{ "year": "2021", "europe": 5, "namerica": 2.5, "asia": 1 }, { "year": "2022", "europe": 2.6, "namerica": 6.7, "asia": 2.2 }, { "year": "2023", "europe": 4.8, "namerica": 1.9, "asia": 4.4 }];
//     v-- omit
const {year, ...r} = Object.assign({}, ...data);
const keys = Object.keys(r);
console.log(keys);

With an array of omit keys, you can replace the destructuring with .filter() on Object.keys():

const data = [{ "year": "2021", "europe": 5, "namerica": 2.5, "asia": 1 }, { "year": "2022", "europe": 2.6, "namerica": 6.7, "asia": 2.2 }, { "year": "2023", "europe": 4.8, "namerica": 1.9, "asia": 4.4 }];

const omit = ['year'];
const merged = Object.assign({}, ...data);
const keys = Object.keys(merged).filter(key => !omit.includes(key));
console.log(keys);

I prefer a Set with filter to a reduce here.

Note the flatMap too

Filter at the end is more efficient (thanks @Nick):

const data = [{ "year": "2021", "europe": 5, "namerica": 2.5, "asia": 1 }, { "year": "2022", "europe": 2.6, "namerica": 6.7, "asia": 2.2 }, { "year": "2023", "europe": 4.8, "namerica": 1.9, "asia": 4.4 }]; 
const omit = ["year"];

const uniqueLables =  [...new Set(
    data.flatMap(item => Object.keys(item))
  )].filter(key => !omit.includes(key));

console.log(uniqueLables) // => ['europe', 'namerica', 'asia']

You could just use a set to collect the keys, adding every key seen while iterating data. Then just delete the keys in omit:

const data = [{
  "year": "2021",
  "europe": 5,
  "namerica": 2.5,
  "asia": 1
}, {
  "year": "2022",
  "europe": 2.6,
  "namerica": 6.7,
  "asia": 2.2
}, {
  "year": "2023",
  "europe": 4.8,
  "namerica": 1.9,
  "asia": 4.4
}];

const omit = ['year']

const uniqueLabels = new Set(data.flatMap(o => Object.keys(o)))
omit.forEach(k => uniqueLabels.delete(k))

console.log([...uniqueLabels])

Here is the solution, you could do the below:

const data = [{
    "year": "2021",
    "europe": 5,
    "namerica": 2.5,
    "asia": 1
  }, {
    "year": "2022",
    "europe": 2.6,
    "namerica": 6.7,
    "asia": 2.2,
  }, {
    "year": "2023",
    "europe": 4.8, 
    "namerica": 1.9,
    "asia": 4.4,
}];
let omits = ['year'];
const result = Object.keys(Object.assign({}, ...data)).filter(e => !omits.includes(e));

console.log(result)

You can try this:

  1. Use an object to accumulate unique keys instead of array. This will allow you to skip uniqueLables.includes check. You can use Object.keys to get list at the end
  2. Use array methods for loop. This will allow you to reduce mutation.

const data = [{ "year": "2021", "europe": 5, "namerica": 2.5, "asia": 1 }, { "year": "2022", "europe": 2.6, "namerica": 6.7, "asia": 2.2 }, { "year": "2023", "europe": 4.8, "namerica": 1.9,"asia": 4.4 }];

const omit = ["year"]

const temp = data.reduce((acc, obj) => {
  Object.keys(obj).forEach((key) => {
    if (!omit.includes(key))
      acc[key] = 0;
  })
  return acc;
}, {})
const uniqueLables = Object.keys(temp);
console.log(uniqueLables)

You can use reduce method to accumulate the array and Set to only insert unique values.

const data = [{
  "year": "2021",
  "europe": 5,
  "namerica": 2.5,
  "asia": 1
}, {
  "year": "2022",
  "europe": 2.6,
  "namerica": 6.7,
  "asia": 2.2
}, {
  "year": "2023",
  "europe": 4.8, 
  "namerica": 1.9,
  "asia": 4.4
}];

const omit = ["year"]

const result = data.reduce((acc, o) => {
  let filteredKeys = Object.keys(o).filter(k => !omit.includes(k));
  return new Set([...acc, ...filteredKeys])
}, new Set())

console.log([...result])

Hmm interesting. My implementation would go like this:

const data = [{
  "year": "2021",
  "europe": 5,
  "namerica": 2.5,
  "asia": 1
}, {
  "year": "2022",
  "europe": 2.6,
  "namerica": 6.7,
  "asia": 2.2
}, {
  "year": "2023",
  "europe": 4.8,
  "namerica": 1.9,
  "asia": 4.4
}];

const uniqueLabels = [];
const omit = ["year"]
//create a map of omited keys
const map = {}
omit.forEach((el) => map[el] = true)
//create map of added keys 
const keyAdded = {}
//only traverse data 
data.forEach((el) => {
   Object.entries(el).forEach(([key, value]) => {
    if(!(key in map) && !(key in keyAdded)) {
       uniqueLabels.push(key) 
       keyAdded[key] = true
    }
   })
})


console.log(uniqueLabels) // => ['europe', 'namerica', 'asia']

In fact, the method in question more correctly, because this is core js;

const data = [{
    year: "2021",
    europe: 5,
    namerica: 2.5,
    asia: 1,
  },
  {
    year: "2022",
    europe: 2.6,
    namerica: 6.7,
    asia: 2.2,
  },
  {
    year: "2023",
    europe: 4.8,
    namerica: 1.9,
    asia: 4.4,
  },
];

const arr = [];
const omit = ["year"];

for (let item of data) {
  arr.push(...Object.keys(item));
}

const uniqueLables = new Set(arr);
for (let key of omit) {
  uniqueLables.delete(key);
}

console.log([...uniqueLables]);

Related