equivalence-classes.ts 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. /**
  2. * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. export class EquivalenceClassesImpl<K, V> {
  7. private id = 0;
  8. private byHash = new Map<number, { id: number, keys: K[], value: V }[]>();
  9. readonly groups: K[][] = [];
  10. private createGroup(key: K, value: V) {
  11. const id = this.id++;
  12. const keys = [key];
  13. this.groups[id] = keys;
  14. return { id, keys, value };
  15. }
  16. // Return the group representative.
  17. add(key: K, a: V) {
  18. const hash = this.getHash(a);
  19. if (this.byHash.has(hash)) {
  20. const groups = this.byHash.get(hash)!;
  21. for (let i = 0, _i = groups.length; i < _i; i++) {
  22. const group = groups[i];
  23. if (this.areEqual(a, group.value)) {
  24. group.keys[group.keys.length] = key;
  25. return group.value;
  26. }
  27. }
  28. const group = this.createGroup(key, a);
  29. groups[groups.length] = group;
  30. return group.value;
  31. } else {
  32. const group = this.createGroup(key, a);
  33. this.byHash.set(hash, [group]);
  34. return group.value;
  35. }
  36. }
  37. constructor(private getHash: (v: V) => any, private areEqual: (a: V, b: V) => boolean) { }
  38. }
  39. export function EquivalenceClasses<K, V>(getHash: (x: V) => any, areEqual: (a: V, b: V) => boolean) {
  40. return new EquivalenceClassesImpl<K, V>(getHash, areEqual);
  41. }