4

I have an Array of Objects. Every object in this Array has some Keypairs. One of this Keypairs ("obj", for example) is an Array of Objects too.

Example what I have:

const arrOfObj = [
  { 
    "id": 1
    "obj": {
      "arr1": ["arr1-1"],
      "arr2": ["arr2-1", "arr2-2"],
      "arr3": ["arr3-1", "arr3-2"]
    }
  },
  { 
    "id": 1
    "obj": {
      "arr1": ["arr1-2"],
      "arr2": ["arr2-1", "arr2-3"],
      "arr3": ["arr3-1", "arr3-3"],
      "arr4": ["arr4-1"],
    }
  },
];

I need to get new Object of "obj" Objects with unique keys and unique elements inside them.

Example what I need:

const newObj = {
   "arr1": ["arr1-1", "arr1-2"],
   "arr2": ["arr2-1", "arr2-2", "arr2-3"],
   "arr3": ["arr3-1", "arr3-2", "arr3-3"],
   "arr4": ["arr4-1"],
}

All of this comes dynamically from API by request, so I don`t know the names of this keypairs, but i need to store them.

I have Solution, but I`m new in JavaScript, and want to know how to simplify and improve my poor Code.

1. First, I`m defining the new Object and retrieving the Names for his keypairs from "arrOfObj".

let filterObj = {};

arrOfObj.forEach(function (item) {
  for (let key in item.obj) {
    filterObj[key] = [];
  }
});

2. After that I`m getting all the Elements of every Array from "arrOfObj" and store them in new Object "filterObj" in the Keypair with the same Name.

arrOfObj.forEach(function (item) {
  for (let key in item.obj) {
    for (let element = 0; element < item.obj[key].length; element++) {
      filterObj[key].push(item.obj[key][element]);
    }
  }
});

3. To the end I`m filtering Arrays to get unique Elements only.

for (let key in filterObj) {
  filterObj[key] = Array.from(new Set(filterObj[key]));
}

It works, I`ve got what I want, but it seems to much monstrously. How this code can be simplified the best way?

Thanks for the help and advices.

7
  • 1
    Overall what you have is not bad and it's not spaghetti code. It's easy to follow each step. There are some shortcuts like iterating Object.entries() but being able to do all this long hand as you have done is good learning experience Commented May 1, 2021 at 20:48
  • @charlietfl Thank You:) But I want to improve my JS-Skill and I`m totally sure that all of this can and must be written in much more simple and better way... Commented May 1, 2021 at 20:50
  • 1
    "Much simpler" ... there are techniques to perhaps condense it some but then you may not find it as readable or maintainable if it's not as clear as what you currently have. One suggestion is use forEach() in step two instead of the more verbose for loop Commented May 1, 2021 at 20:54
  • @charlietfl Got it, thank You one more time ^-^ Commented May 1, 2021 at 20:56
  • 1
    And read up on how Object.keys() , Object.values() and Object.entries() work Commented May 1, 2021 at 20:57

2 Answers 2

1

You can use some destructuring and Object.entries() and Object.keys() to streamline this and do everything to the new Object only

const newObj  = {}

arrOfObj.forEach(({obj}) => {
    Object.entries(obj).forEach(([k, arr]) => {
       newObj[k] = newObj[k] || [];
       newObj[k].push(...arr);
    })
});

Object.keys(newObj).forEach(k => newObj[k] = [...new Set(newObj[k])]);

console.log(newObj)
<script>
const arrOfObj=[{id:1,obj:{arr1:["arr1-1"],arr2:["arr2-1","arr2-2"],arr3:["arr3-1","arr3-2"]}},{id:1,obj:{arr1:["arr1-2"],arr2:["arr2-1","arr2-3"],arr3:["arr3-1","arr3-3"],arr4:["arr4-1"]}}];
</script>

Sign up to request clarification or add additional context in comments.

1 Comment

Very elegant. I have learned much new from this snippet, thank You ^-^
1

Another solution using Object#fromEntries, Array#reduce, Object#entries, Array#forEach, Set, and Map:

const arrOfObj = [ { "id": 1, "obj": { "arr1": ["arr1-1"], "arr2": ["arr2-1", "arr2-2"], "arr3": ["arr3-1", "arr3-2"] } }, { "id": 1, "obj": { "arr1": ["arr1-2"], "arr2": ["arr2-1", "arr2-3"], "arr3": ["arr3-1", "arr3-3"], "arr4": ["arr4-1"] } } ];

const filterObj = 
  // transform the resulting list of key-values pairs to an object at the end
  Object.fromEntries(
    // get a map of array name as key and its unique items as value
    [...arrOfObj.reduce((map, { obj = {} }) => {
      // iterate over current element's object to update the map
      Object.entries(obj).forEach(([currentKey, currentValues]) => {
        const keyValues = [...(map.get(currentKey) || []), ...currentValues];
        map.set(currentKey, [...new Set(keyValues)]);
      });
      return map;
    }, new Map)]
  );

console.log(filterObj);

1 Comment

@Agatha you're welcome. Make sure to read the docs for better understanding!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.