Skip to content

Commit d911874

Browse files
committed
Add basic set methods.
1 parent ace4b50 commit d911874

16 files changed

+280
-61
lines changed

README.md

Lines changed: 114 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -45,72 +45,13 @@ var min = d3.min(array);
4545

4646
## API Reference
4747

48-
* [Iterables](#iterables)
4948
* [Statistics](#statistics)
5049
* [Search](#search)
5150
* [Transformations](#transformations)
51+
* [Iterables](#iterables)
52+
* [Sets](#sets)
5253
* [Bins](#bins)
5354

54-
### Iterables
55-
56-
These are equivalent to built-in array methods, but work with any iterable including Map, Set, and Generator.
57-
58-
<a name="every" href="#every">#</a> d3.<b>every</b>(<i>iterable</i>, <i>test</i>) · [Source](https://github.com/d3/d3-array/blob/master/src/every.js)
59-
60-
Returns true if the given *test* function returns true for every value in the given *iterable*. This method returns as soon as *test* returns a non-truthy value or all values are iterated over. Equivalent to [*array*.every](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every):
61-
62-
```js
63-
Array.from(iterable).every(test)
64-
```
65-
66-
<a name="some" href="#some">#</a> d3.<b>some</b>(<i>iterable</i>, <i>test</i>) · [Source](https://github.com/d3/d3-array/blob/master/src/some.js)
67-
68-
Returns true if the given *test* function returns true for any value in the given *iterable*. This method returns as soon as *test* returns a truthy value or all values are iterated over. Equivalent to [*array*.some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some):
69-
70-
```js
71-
Array.from(iterable).some(test)
72-
```
73-
74-
<a name="filter" href="#filter">#</a> d3.<b>filter</b>(<i>iterable</i>, <i>test</i>) · [Source](https://github.com/d3/d3-array/blob/master/src/filter.js)
75-
76-
Returns a new array containing the values from *iterable*, in order, for which the given *test* function returns true. Equivalent to [*array*.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter):
77-
78-
```js
79-
Array.from(iterable).filter(test)
80-
```
81-
82-
<a name="map" href="#map">#</a> d3.<b>map</b>(<i>iterable</i>, <i>mapper</i>) · [Source](https://github.com/d3/d3-array/blob/master/src/map.js)
83-
84-
Returns a new array containing the mapped values from *iterable*, in order, as defined by given *mapper* function. Equivalent to [*array*.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) and [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from):
85-
86-
```js
87-
Array.from(iterable, mapper)
88-
```
89-
90-
<a name="reduce" href="#reduce">#</a> d3.<b>reduce</b>(<i>iterable</i>, <i>reducer</i>[, <i>initialValue</i>]) · [Source](https://github.com/d3/d3-array/blob/master/src/reduce.js)
91-
92-
Returns the reduced value defined by given *reducer* function, which is repeatedly invoked for each value in *iterable*, being passed the current reduced value and the next value. Equivalent to [*array*.reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce):
93-
94-
```js
95-
Array.from(iterable).reduce(reducer, initialValue)
96-
```
97-
98-
<a name="reverse" href="#reverse">#</a> d3.<b>reverse</b>(<i>iterable</i>) · [Source](https://github.com/d3/d3-array/blob/master/src/reverse.js)
99-
100-
Returns an array containing the values in the given *iterable* in reverse order. Equivalent to [*array*.reverse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse), except that it does not mutate the given *iterable*:
101-
102-
```js
103-
Array.from(iterable).reverse()
104-
```
105-
106-
<a name="sort" href="#sort">#</a> d3.<b>sort</b>(<i>iterable</i>, <i>comparator</i> = d3.ascending) · [Source](https://github.com/d3/d3-array/blob/master/src/sort.js)
107-
108-
Returns an array containing the values in the given *iterable* in the sorted order defined by the given *comparator* function. If *comparator* is not specified, it defaults to [d3.ascending](#ascending). Equivalent to [*array*.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort), except that it does not mutate the given *iterable*, and the comparator defaults to natural order instead of lexicographic order:
109-
110-
```js
111-
Array.from(iterable).sort(comparator)
112-
```
113-
11455
### Statistics
11556

11657
Methods for computing basic summary statistics.
@@ -678,6 +619,118 @@ Returns an array of arrays, where the *i*th array contains the *i*th element fro
678619
d3.zip([1, 2], [3, 4]); // returns [[1, 3], [2, 4]]
679620
```
680621

622+
### Iterables
623+
624+
These are equivalent to built-in array methods, but work with any iterable including Map, Set, and Generator.
625+
626+
<a name="every" href="#every">#</a> d3.<b>every</b>(<i>iterable</i>, <i>test</i>) · [Source](https://github.com/d3/d3-array/blob/master/src/every.js)
627+
628+
Returns true if the given *test* function returns true for every value in the given *iterable*. This method returns as soon as *test* returns a non-truthy value or all values are iterated over. Equivalent to [*array*.every](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every):
629+
630+
```js
631+
d3.every(new Set([1, 3, 5, 7]), x => x & 1) // true
632+
```
633+
634+
<a name="some" href="#some">#</a> d3.<b>some</b>(<i>iterable</i>, <i>test</i>) · [Source](https://github.com/d3/d3-array/blob/master/src/some.js)
635+
636+
Returns true if the given *test* function returns true for any value in the given *iterable*. This method returns as soon as *test* returns a truthy value or all values are iterated over. Equivalent to [*array*.some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some):
637+
638+
```js
639+
d3.some(new Set([0, 2, 3, 4]), x => x & 1) // true
640+
```
641+
642+
<a name="filter" href="#filter">#</a> d3.<b>filter</b>(<i>iterable</i>, <i>test</i>) · [Source](https://github.com/d3/d3-array/blob/master/src/filter.js)
643+
644+
Returns a new array containing the values from *iterable*, in order, for which the given *test* function returns true. Equivalent to [*array*.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter):
645+
646+
```js
647+
d3.filter(new Set([0, 2, 3, 4]), x => x & 1) // [3]
648+
```
649+
650+
<a name="map" href="#map">#</a> d3.<b>map</b>(<i>iterable</i>, <i>mapper</i>) · [Source](https://github.com/d3/d3-array/blob/master/src/map.js)
651+
652+
Returns a new array containing the mapped values from *iterable*, in order, as defined by given *mapper* function. Equivalent to [*array*.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) and [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from):
653+
654+
```js
655+
d3.map(new Set([0, 2, 3, 4]), x => x & 1) // [0, 0, 1, 0]
656+
```
657+
658+
<a name="reduce" href="#reduce">#</a> d3.<b>reduce</b>(<i>iterable</i>, <i>reducer</i>[, <i>initialValue</i>]) · [Source](https://github.com/d3/d3-array/blob/master/src/reduce.js)
659+
660+
Returns the reduced value defined by given *reducer* function, which is repeatedly invoked for each value in *iterable*, being passed the current reduced value and the next value. Equivalent to [*array*.reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce):
661+
662+
```js
663+
d3.reduce(new Set([0, 2, 3, 4]), (p, v) => p + v, 0) // 9
664+
```
665+
666+
<a name="reverse" href="#reverse">#</a> d3.<b>reverse</b>(<i>iterable</i>) · [Source](https://github.com/d3/d3-array/blob/master/src/reverse.js)
667+
668+
Returns an array containing the values in the given *iterable* in reverse order. Equivalent to [*array*.reverse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse), except that it does not mutate the given *iterable*:
669+
670+
```js
671+
d3.reverse(new Set([0, 2, 3, 1])) // [1, 3, 2, 0]
672+
```
673+
674+
<a name="sort" href="#sort">#</a> d3.<b>sort</b>(<i>iterable</i>, <i>comparator</i> = d3.ascending) · [Source](https://github.com/d3/d3-array/blob/master/src/sort.js)
675+
676+
Returns an array containing the values in the given *iterable* in the sorted order defined by the given *comparator* function. If *comparator* is not specified, it defaults to [d3.ascending](#ascending). Equivalent to [*array*.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort), except that it does not mutate the given *iterable*, and the comparator defaults to natural order instead of lexicographic order:
677+
678+
```js
679+
d3.sort(new Set([0, 2, 3, 1])) // [0, 1, 2, 3]
680+
```
681+
682+
### Sets
683+
684+
This methods implement basic set operations for any iterable.
685+
686+
<a name="difference" href="#difference">#</a> d3.<b>difference</b>(<i>iterable</i>, ...<i>others</i>) · [Source](https://github.com/d3/d3-array/blob/master/src/difference.js)
687+
688+
Returns a new Set containing every value in *iterable* that is not in any of the *others* iterables.
689+
690+
```js
691+
d3.difference([0, 1, 2, 0], [1]) // Set {0, 2}
692+
```
693+
694+
<a name="union" href="#union">#</a> d3.<b>union</b>(...<i>iterables</i>) · [Source](https://github.com/d3/d3-array/blob/master/src/union.js)
695+
696+
Returns a new Set containing every (distinct) value that appears in any of the given *iterables*. The order of values in the returned Set is based on their first occurrence in the given *iterables*.
697+
698+
```js
699+
d3.union([0, 2, 1, 0], [1, 3]) // Set {0, 2, 1, 3}
700+
```
701+
702+
<a name="intersection" href="#intersection">#</a> d3.<b>intersection</b>(...<i>iterables</i>) · [Source](https://github.com/d3/d3-array/blob/master/src/intersection.js)
703+
704+
Returns a new Set containing every (distinct) value that appears in all of the given *iterables*. The order of values in the returned Set is based on their first occurrence in the given *iterables*.
705+
706+
```js
707+
d3.intersection([0, 2, 1, 0], [1, 3]) // Set {1}
708+
```
709+
710+
<a name="superset" href="#superset">#</a> d3.<b>superset</b>(<i>a</i>, <i>b</i>) · [Source](https://github.com/d3/d3-array/blob/master/src/superset.js)
711+
712+
Returns true if *a* is a superset of *b*: if every value in the given iterable *b* is also in the given iterable *a*.
713+
714+
```js
715+
d3.superset([0, 2, 1, 3, 0], [1, 3]) // true
716+
```
717+
718+
<a name="subset" href="#subset">#</a> d3.<b>subset</b>(<i>a</i>, <i>b</i>) · [Source](https://github.com/d3/d3-array/blob/master/src/subset.js)
719+
720+
Returns true if *a* is a subset of *b*: if every value in the given iterable *a* is also in the given iterable *b*.
721+
722+
```js
723+
d3.subset([1, 3], [0, 2, 1, 3, 0]) // true
724+
```
725+
726+
<a name="disjoint" href="#disjoint">#</a> d3.<b>disjoint</b>(<i>a</i>, <i>b</i>) · [Source](https://github.com/d3/d3-array/blob/master/src/disjoint.js)
727+
728+
Returns true if *a* and *b* are disjoint: if *a* and *b* contain no shared value.
729+
730+
```js
731+
d3.disjoint([1, 3], [2, 4]) // true
732+
```
733+
681734
### Bins
682735

683736
[<img src="https://raw.githubusercontent.com/d3/d3-array/master/img/histogram.png" width="480" height="250" alt="Histogram">](http://bl.ocks.org/mbostock/3048450)

src/difference.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export default function difference(values, ...others) {
2+
values = new Set(values);
3+
for (const other of others) {
4+
for (const value of other) {
5+
values.delete(value);
6+
}
7+
}
8+
return values;
9+
}

src/disjoint.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import set from "./set.js";
2+
3+
export default function disjoint(values, other) {
4+
other = set(other);
5+
for (const value of values) {
6+
if (other.has(value)) {
7+
return false;
8+
}
9+
}
10+
return true;
11+
}

src/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,9 @@ export {default as map} from "./map.js";
4444
export {default as reduce} from "./reduce.js";
4545
export {default as reverse} from "./reverse.js";
4646
export {default as sort} from "./sort.js";
47+
export {default as difference} from "./difference.js";
48+
export {default as disjoint} from "./disjoint.js";
49+
export {default as intersection} from "./intersection.js";
50+
export {default as subset} from "./subset.js";
51+
export {default as superset} from "./superset.js";
52+
export {default as union} from "./union.js";

src/intersection.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import set from "./set.js";
2+
3+
export default function intersection(values, ...others) {
4+
values = new Set(values);
5+
others = others.map(set);
6+
out: for (const value of values) {
7+
for (const other of others) {
8+
if (!other.has(value)) {
9+
values.delete(value);
10+
continue out;
11+
}
12+
}
13+
}
14+
return values;
15+
}

src/set.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function set(values) {
2+
return values instanceof Set ? values : new Set(values);
3+
}

src/subset.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import superset from "./superset.js";
2+
3+
export default function subset(values, other) {
4+
return superset(other, values);
5+
}

src/superset.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import set from "./set.js";
2+
3+
export default function superset(values, other) {
4+
values = set(values);
5+
for (const value of other) {
6+
if (!values.has(value)) {
7+
return false;
8+
}
9+
}
10+
return true;
11+
}

src/union.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export default function union(...others) {
2+
const set = new Set();
3+
for (const other of others) {
4+
for (const o of other) {
5+
set.add(o);
6+
}
7+
}
8+
return set;
9+
}

test/difference-test.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const tape = require("tape-await");
2+
const d3 = require("../");
3+
4+
require("./setEqual");
5+
6+
tape("difference(values, other) returns a set of values", (test) => {
7+
test.setEqual(d3.difference([1, 2, 3], [2, 1]), new Set([3]));
8+
test.setEqual(d3.difference([1, 2], [2, 3, 1]), new Set([]));
9+
test.setEqual(d3.difference([2, 1, 3], [4, 3, 1]), new Set([2]));
10+
});
11+
12+
tape("difference(...values) accepts iterables", (test) => {
13+
test.setEqual(d3.difference(new Set([1, 2, 3]), new Set([1])), new Set([2, 3]));
14+
});

0 commit comments

Comments
 (0)