Skip to content

Commit 9a8fc06

Browse files
committed
feat: disjointSet getAllSets
1 parent 62930b2 commit 9a8fc06

File tree

2 files changed

+57
-6
lines changed

2 files changed

+57
-6
lines changed

libraries/rush-lib/src/logic/cobuild/DisjointSet.ts

+34-6
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,23 @@ import { InternalError } from '@rushstack/node-core-library';
77
* A disjoint set data structure
88
*/
99
export class DisjointSet<T extends object> {
10-
private _forest: WeakSet<T>;
11-
private _parentMap: WeakMap<T, T>;
12-
private _sizeMap: WeakMap<T, number>;
10+
private _forest: Set<T>;
11+
private _parentMap: Map<T, T>;
12+
private _sizeMap: Map<T, number>;
13+
private _setByElement: Map<T, Set<T>> | undefined;
1314

1415
public constructor() {
15-
this._forest = new WeakSet<T>();
16-
this._parentMap = new WeakMap<T, T>();
17-
this._sizeMap = new WeakMap<T, number>();
16+
this._forest = new Set<T>();
17+
this._parentMap = new Map<T, T>();
18+
this._sizeMap = new Map<T, number>();
19+
this._setByElement = new Map<T, Set<T>>();
20+
}
21+
22+
public destroy(): void {
23+
this._forest.clear();
24+
this._parentMap.clear();
25+
this._sizeMap.clear();
26+
this._setByElement?.clear();
1827
}
1928

2029
/**
@@ -28,6 +37,7 @@ export class DisjointSet<T extends object> {
2837
this._forest.add(x);
2938
this._parentMap.set(x, x);
3039
this._sizeMap.set(x, 1);
40+
this._setByElement = undefined;
3141
}
3242

3343
/**
@@ -49,6 +59,24 @@ export class DisjointSet<T extends object> {
4959
}
5060
this._parentMap.set(y, x);
5161
this._sizeMap.set(x, this._getSize(x) + this._getSize(y));
62+
this._setByElement = undefined;
63+
}
64+
65+
public getAllSets(): Iterable<Set<T>> {
66+
if (this._setByElement === undefined) {
67+
this._setByElement = new Map<T, Set<T>>();
68+
69+
for (const element of this._forest) {
70+
const root: T = this._find(element);
71+
let set: Set<T> | undefined = this._setByElement.get(root);
72+
if (set === undefined) {
73+
set = new Set<T>();
74+
this._setByElement.set(root, set);
75+
}
76+
set.add(element);
77+
}
78+
}
79+
return this._setByElement.values();
5280
}
5381

5482
/**

libraries/rush-lib/src/logic/cobuild/test/DisjointSet.test.ts

+23
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,27 @@ describe(DisjointSet.name, () => {
7979
expect(disjointSet.isConnected(obj1, obj3)).toBe(false);
8080
expect(disjointSet.isConnected(obj1, obj4)).toBe(false);
8181
});
82+
83+
it('can get all sets', () => {
84+
const disjointSet = new DisjointSet<{ id: number }>();
85+
const obj1 = { id: 1 };
86+
const obj2 = { id: 2 };
87+
const obj3 = { id: 3 };
88+
disjointSet.add(obj1);
89+
disjointSet.add(obj2);
90+
disjointSet.add(obj3);
91+
92+
disjointSet.union(obj1, obj2);
93+
94+
const allSets: Iterable<Set<{ id: number }>> = disjointSet.getAllSets();
95+
96+
const allSetList: Array<Set<{ id: number }>> = [];
97+
for (const set of allSets) {
98+
allSetList.push(set);
99+
}
100+
101+
expect(allSetList.length).toBe(2);
102+
expect(Array.from(allSetList[0]).map((x) => x.id)).toEqual(expect.arrayContaining([1, 2]));
103+
expect(Array.from(allSetList[1]).map((x) => x.id)).toEqual(expect.arrayContaining([3]));
104+
});
82105
});

0 commit comments

Comments
 (0)