PMO1948
PMO1948

Reputation: 2554

Create set of sets javascript

I have a group of arrays that I need to filter out duplicates. It needs to work in such a fashion that within each array, there are no duplicates, and within the total group, there are no two arrays that hold the same values.

The first part is easy - for each inner array, I can apply Set to the array and filter it out. So, given the matrix arrays I can apply the following to filter:

const sets : string[][] = arrays.map(arr=>[...new Set(arr)].sort());

This will give me an array of sets. How can I make this into a set of sets? As in, if sets=[[a, b],[c],[d, a],[c],[e]] I would like setOfSets to equal [[a, b],[c],[d, a],[e]]?

Applying setOfSets = [...new Set(sets)]; would not work, since arrays that are equal are not considered equal by default if they have different addresses. Is there a way to force set to check by value, or another effective way to create this effect?

Edit

Original matrix:

[[a, b, b],
[c,c],
[b,a],
[d,a],
[c,c],
[e,e]]

after creating and sorting sets:

[[a,b],
[c],
[a,b],
[d,a],
[c],
[e]]

desired result:

[[a,b],
[c],
[d,a],
[e]]

Upvotes: 3

Views: 727

Answers (1)

user3297291
user3297291

Reputation: 23372

If the data in your set is easy to serialize, I would opt for a solution like this:

const data = [
  ["a", "b", "b"],
  ["c","c"],
  ["b","a"],
  ["d","a"],
  ["c","c"],
  ["e","e"]
];

// Create the "hash" of your set
const serializeSet = s => Array
  .from(s)
  .sort()
  .join("___");

// Create a map (or object) that ensures 1 entry per hash
const outputMap = data
  .map(xs => new Set(xs))
  .reduce(
    (acc, s) => acc.set(serializeSet(s), s),
    new Map()
  );

// Turn your Map and Sets back in to arrays
const output = Array
  .from(outputMap.values())
  .map(s => Array.from(s));
  
console.log(output);

To come up with a good hash function for your set, you need to have a good look at your data. For example:

  • When your arrays consist of single characters from a-z, like in my example above, we can sort those strings using a default sorter and then join the result using a character from outside the a-z range.
  • If your arrays consist of random strings or numbers, JSON.stringify(Array.from(s).sort()) is safer to use
  • When your arrays consist of plain objects, you could JSON.stringify its sorted elements, but watch out for differences in the order of objects properties! (e.g. {a: 1, b: 2} vs {b: 2, a: 1})

Upvotes: 4

Related Questions