Home > Enterprise >  How to get the values of an array of an array of objects
How to get the values of an array of an array of objects

Time:09-27

So I have an array like this. Like array containing an array of objects.

posts = [
  [
    {
      "id": 2,
      "info": "This is some information"
    },
    {
      "id": 3,
      "info": "This is the other information"
    }
  ],
  [
    {
      "id": 2,
      "info": "This is a duplicated id I want to remove"
    },
    {
      "id": 4,
      "info": "This information is safe"
    }
  ]
]

I want to get the elements from each array and create a new array that only has the objects at the same time removing duplicated ids. What am trying to achieve is something like

posts = [
   {
      "id": 2,
      "info": "This is some information"
    },
    {
      "id": 3,
      "info": "This is the other information"
    },
      {
      "id": 4,
      "info": "This information is safe"
    }
]

This is the code I have so far

id = ids.map(val => {
  for(let i in val) {
    console.log(val)
  }
return something
})

I keep getting undefined values. I have tried forEach, for loop. Any help would be much appreciated. Thanks

CodePudding user response:

Use flat to get a flattened array of objects, and then loop over the array. If the current object's id can't be found in an object in the output array push that object.

const posts=[[{id:2,info:"This is some information"},{id:3,info:"This is the other information"}],[{id:2,info:"This is a duplicated id I want to remove"},{id:4,info:"This information is safe"}]];

const out = [];

for (const obj of posts.flat()) {
  const found = out.find(f => obj.id === f.id);
  if (!found) out.push(obj);
}

console.log(out);

CodePudding user response:

I group by id in order to remove duplicates.

var posts = [[{id:2,info:"This is some information"},{id:3,info:"This is the other information"}],[{id:2,info:"This is a duplicated id I want to remove"},{id:4,info:"This information is safe"}]];

var agg = {}
posts.forEach(function(arr) {
  arr.forEach(function(item) {
    agg[item.id] = agg[item.id] || item
  })
})

console.log(Object.values(agg))
.as-console-wrapper {
  max-height: 100% !important
}

CodePudding user response:

Flatten the array with flat, then use a set to keep track of the ids we already have. The ternary inside the filter is logic to check if the id is already in the set, and if it is, we filter the item out. Otherwise, we add the id back to the set.

const posts = [[{id:2,info:"This is some information"},{id:3,info:"This is the other information"}],[{id:2,info:"This is a duplicated id I want to remove"},{id:4,info:"This information is safe"}]];

const flat = posts.flat();

const ids = new Set();

const filtered = flat.filter((item) => ids.has(item.id) ? false : ids.add(item.id));

console.log(filtered);
.as-console-wrapper {
  max-height: 100% !important
}

CodePudding user response:

There are two things we need to do:

  • Flatten the inner areas into one main array with array.prototype.flat()
  • Remove duplicates based on, I'm assuming, the order of their appearance in the data.
    • We can do this by reducing the flattened array to an object with a condition that doesn't add any present id's if they're found
    • Then we convert that object to an array using Object.values()

let posts = [ [ { "id": 2, "info": "This is some information" }, { "id": 3, "info": "This is the other information" } ], [ { "id": 2, "info": "This is a duplicated id I want to remove" }, { "id": 4, "info": "This information is safe" } ] ]

let flattened = posts.flat()
console.log('Flattened: ', flattened)

let unique = flattened.reduce((acc, obj) => {
  if (!acc[obj.id]) {
    acc[obj.id] = obj
  }
  return acc
}, {})
console.log('Unique Objects: ', unique)

let result = Object.values(unique)
console.log('Final Array: ' ,result)

Doing it in one go and with a spread ... object merge:

let posts = [ [ { "id": 2, "info": "This is some information" }, { "id": 3, "info": "This is the other information" } ], [ { "id": 2, "info": "This is a duplicated id I want to remove" }, { "id": 4, "info": "This information is safe" } ] ]

let result = Object.values(
  posts.flat().reduce((acc, obj) => 
    ({...{[obj.id]: obj}, ...acc})
  , {})
);
console.log('Final Array: ', result);

CodePudding user response:

You could use .flat() and then .filter():

const posts = [
    [
        {
            id: 2,
            info: 'This is some information',
        },
        {
            id: 3,
            info: 'This is the other information',
        },
    ],
    [
        {
            id: 2,
            info: 'This is a duplicated id I want to remove',
        },
        {
            id: 4,
            info: 'This information is safe',
        },
    ],
];

const newPosts = posts.flat().filter((x, i, self) => i === self.findIndex((y) => x.id === y.id));

console.log(newPosts);

Another potential (and more optimal) solution could be this using .reduce():

const posts = [
    [
        {
            id: 2,
            info: 'This is some information',
        },
        {
            id: 3,
            info: 'This is the other information',
        },
    ],
    [
        {
            id: 2,
            info: 'This is a duplicated id I want to remove',
        },
        {
            id: 4,
            info: 'This information is safe',
        },
    ],
];

const newPosts = Object.values(posts.flat().reduce((acc, curr) => {
    return {
        ...acc,
        ...(!acc[curr.id] ? { [curr.id]: curr } : undefined),
    };
}, {}));

console.log(newPosts);

Or, if you don't like .reduce(), you can do something very similar with the Map object and a for...of loop:

const posts = [
    [
        {
            id: 2,
            info: 'This is some information',
        },
        {
            id: 3,
            info: 'This is the other information',
        },
    ],
    [
        {
            id: 2,
            info: 'This is a duplicated id I want to remove',
        },
        {
            id: 4,
            info: 'This information is safe',
        },
    ],
];

const map = new Map();

for (const item of posts.flat()) {
    if (map.has(item.id)) continue;

    map.set(item.id, item);
}

const newPosts = Array.from(map.values());

console.log(newPosts);

Or even use a classic for loop to get the job done:

const posts = [
    [
        {
            id: 2,
            info: 'This is some information',
        },
        {
            id: 3,
            info: 'This is the other information',
        },
    ],
    [
        {
            id: 2,
            info: 'This is a duplicated id I want to remove',
        },
        {
            id: 4,
            info: 'This information is safe',
        },
    ],
];

const flattened = posts.flat();
const map = {};

for (let i = 0; i < flattened.length; i  ) {
    if (map[flattened[i].id]) continue;

    map[flattened[i].id] = flattened[i];
}

console.log(Object.values(map));

Either way, in each of these examples we're following the same workflow:

  1. Flatten the array so that all items are on the same level.
  2. Filter out the items with the duplicate IDs.
  • Related