23

I am attempting to do something very basic in TypeScript. Get a list of unique strings while parsing a map as referenced in this post.

Here is what I am attempting to do:

let myData = new Array<string>();
for (let myObj of this.getAllData()) {
    let name = myObj.name;
    console.log("## we have " + name);
    console.log("### is property ? " + myData.hasOwnProperty(name));
    if (!myData.hasOwnProperty(name)){
        myData.push(name);
    }
}

My printout will always evaluate to false for any string, duplicate or not. Here is some sample output:

 ## we have COW
 ### is property ? false
 ## we have COW
 ### is property ? false
 ## we have RAODN
 ### is property ? false
 ## we have COOL
 ### is property ? false

However, when the process completes, my list contain duplicates. I have tried looking at this documentation, but there is no mention of a 'hashset' or any set in general.

Is there something equivalent in TypeScript of a Set? i.e A list of unique elements

wonea
  • 4,783
  • 17
  • 86
  • 139
angryip
  • 2,140
  • 5
  • 33
  • 67
  • Just for completeness, the original OP doesn't work because push only creates numeric properties based on the indexes. Also, the array solution will give horrible performance - it does a linear search, rather than the hashed access the OP was expecting. – Tony Rietwyk Apr 17 '18 at 03:36

4 Answers4

42

It exists!

mySet: Set<string> = new Set<string>();

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

reggaeguitar
  • 1,795
  • 1
  • 27
  • 48
Marcel
  • 2,810
  • 2
  • 26
  • 46
  • 2
    Careful, fairly recent IE support: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Set – FailedUnitTest Jun 20 '17 at 15:19
  • 5
    But is this a HashSet? `new Set([{}, {}])` and `new Set([new Date(2020,1,1), new Date(2020,1,1)])` produce duplicate entries, whereas in C# only 1 entry persists. – Jeppe May 13 '20 at 06:43
  • 1
    @Jeppe: yes, it's only allows distinct values, but `Date` is a reference type, meaning that `new Date(2020,1,1) == new Date(2020,1,1)` will return false. You would get the same result if you did `hashSet.Add(new object());` twice in C#. – vgru Aug 02 '21 at 11:02
  • @Groo Yeah, in C# it might be specific to `DateTime` since it implements `IEquatable`. Haven't looked deeper into it. Thank you for the comment. – Jeppe Aug 02 '21 at 11:57
3

An object {} is a key value pair dictionary is a hash set in JavaScript which TypeScript is a superset of and therefore you can use a JS object to serve in this role.

A quick version from the code you posted:

let myData = {};
for (let myObj of this.getAllData()) {
    let name = myObj.name;
    if (!myData[name]){
        myData[name] = name;
    }
}
silentsod
  • 8,165
  • 42
  • 40
1

I found my own solution with something like this:

let myData = new Array<string>();
for (let myObj of this.getAllData()) {
    let name = myObj.name;
    if (myData.indexOf(name) == -1){
        myData.push(name);
    }
}

Not sure that it is a better solution than any so far, but it is something I have decided to stick with until a better one is chosen.

angryip
  • 2,140
  • 5
  • 33
  • 67
  • 2
    `if (!myData.indexOf(name) == -1){` - easier to read as `if (myData.indexOf(name) != -1){` – tymeJV Oct 21 '16 at 16:18
  • actually, you caught my mistake in updating this code. I am looking for -1, as they need to be pushed then. @ty – angryip Oct 21 '16 at 16:24
  • 1
    Pretty much all implementations of `Set` will use a hash set under the hood, so they will provide `O(1)` time complexity compared to the `O(n)` complexity of searching the entire array each time (using `indexOf`). If you're rolling your own variant, it would make more sense to just use the fact that all objects are dictionaries in JS (like in @silentsod's answer [below](https://stackoverflow.com/a/40180778/69809)). – vgru Aug 02 '21 at 11:04
0

I found something that looks promising - it's a http://www.timdown.co.uk/jshashtable/jshashset.html

and it contains type definitions for Type Script

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/0b5bfba2994c91a099cd5bcfd984f6c4c39228e5/types/hashset/index.d.ts

It implements a real HashSet - with equals and hashcode functions, buckets etc.

pixel
  • 24,905
  • 36
  • 149
  • 251