Home > Mobile >  flattening, the array of objects and returning the unique array
flattening, the array of objects and returning the unique array

Time:05-10

I have an array that looks like this.

var arr = [{
    "taxname": "MFM",
    "member": [{
      "id": 1334,
      "name": "Mary G. King",
    }, {
      "id": 1324,
      "name": "Bonnie A. Wilson",
    }, {
      "id": 1336,
      "name": "Samantha B. Sellers",
    }]
  },
  {
    "taxname": "Test purpose",
    "member": [{
      "id": 1336,
      "name": "Samantha B. Sellers",
    }]
  },
  {
    "taxname": "New_Test_MF",
    "member": [{
      "id": 1334,
      "name": "Mary G. King",
    }]
  }
];

I have flattened this out so it is just an array of objects.

const result = arr.reduce((r, obj) => r.concat(obj.member), []);

Result:

[{
  id: 1334,
  name: "Mary G. King"
}, {
  id: 1324,
  name: "Bonnie A. Wilson"
}, {
  id: 1336,
  name: "Samantha B. Sellers"
}, {
  id: 1336,
  name: "Samantha B. Sellers"
}, {
  id: 1334,
  name: "Mary G. King"
}]

After that remove the duplicate with id from the result, I did.

const ids = result.map(o => o.id)
const filtered = result.filter(({id}, index) => !ids.includes(id, index   1))

Log the result:

console.log(filtered);

[{
  id: 1324,
  name: "Bonnie A. Wilson"
}, {
  id: 1336,
  name: "Samantha B. Sellers"
}, {
  id: 1334,
  name: "Mary G. King"
}]

I have got the result I wanted. But what is the best way of flattening, the array of objects and returning the unique array instead of using the multiple queries?

CodePudding user response:

I think the way you did it isn't too bad and it's very readable code! Sometimes it's not about writing the most highly performant code, but about writing readable, easily maintainable and extendible code!

That said, here are some other alternatives:

  1. You could combine your steps while reducing using a map to store the IDs as keys for quicker lookup (vs checking an array of ids).
const existingIds = {};
const result = arr.reduce((r, obj) => r.concat(obj.member.filter((m) => {
  if (existingIds.hasOwnProperty(m.id.toString())) {
    return false;
  }

  existingIds[m.id] = true;
  return true;
})), []);
  1. Use the power of Sets (no duplicate elements)!

As a slight modification to your code, you can use a Set to store non-duplicate IDs. This way in your final step, you don't have to do an includes but a find, although you're not trading much here.

const array2 = arr.reduce((r, obj) => r.concat(obj.member), []);
const nonDuplicateIds = Array.from(new Set(array2.map(m => m.id)))
const result2 = nonDuplicateIds.map(id => array2.find(member => member.id === id)) // You could also use an object for faster lookup
  1. Probably my most favorite: Use Objects to make your code even simpler and not require any mapping/filtering!
const members = {};
arr.forEach(data => data.member.forEach((member) => members[member.id] = member));
const result3 = Object.values(members);
  1. Edit: A quick, inefficient one liner where you can kind of do the checks for duplicate elements while reducing!
const result4 = arr.reduce((r, obj) => r.concat(obj.member.filter((m) => r.every(existingM => existingM.id !== m.id))), []);

var arr = [{
    "taxname": "MFM",
    "member": [{
      "id": 1334,
      "name": "Mary G. King",
    }, {
      "id": 1324,
      "name": "Bonnie A. Wilson",
    }, {
      "id": 1336,
      "name": "Samantha B. Sellers",
    }]
  },
  {
    "taxname": "Test purpose",
    "member": [{
      "id": 1336,
      "name": "Samantha B. Sellers",
    }]
  },
  {
    "taxname": "New_Test_MF",
    "member": [{
      "id": 1334,
      "name": "Mary G. King",
    }]
  }
];

// Alternative #1
const existingIds = {};
const result = arr.reduce((r, obj) => r.concat(obj.member.filter((m) => {
  if (existingIds.hasOwnProperty(m.id.toString())) {
    return false;
  }

  existingIds[m.id] = true;
  return true;
})), []);

// Alternative #2
const array2 = arr.reduce((r, obj) => r.concat(obj.member), []);
const nonDuplicateIds = Array.from(new Set(array2.map(m => m.id)))
const result2 = nonDuplicateIds.map(id => array2.find(member => member.id === id)) // You could also use an object for faster lookup

// Alternative #3
const members = {};
arr.forEach(data => data.member.forEach((member) => members[member.id] = member));
const result3 = Object.values(members);

// Alternative #4
const result4 = arr.reduce((r, obj) => r.concat(obj.member.filter((m) => r.every(existingM => existingM.id !== m.id))), []);

console.log(result.length);
console.log(result2.length);
console.log(result3.length);
console.log(result4.length);

CodePudding user response:

you can use flat function in ES10

var arr = [{
    "taxname": "MFM",
    "member": [{
      "id": 1334,
      "name": "Mary G. King",
    }, {
      "id": 1324,
      "name": "Bonnie A. Wilson",
    }, {
      "id": 1336,
      "name": "Samantha B. Sellers",
    }]
  },
  {
    "taxname": "Test purpose",
    "member": [{
      "id": 1336,
      "name": "Samantha B. Sellers",
    }]
  },
  {
    "taxname": "New_Test_MF",
    "member": [{
      "id": 1334,
      "name": "Mary G. King",
    }]
  }
];

var test = arr.map(a => a.member).flat();
var filterd = [...new Set(test.map(t=>t.id))].map(id => test.find(tt => tt.id === id));
console.log(filterd)

  • Related