Socket
Socket
Sign inDemoInstall

subset

Package Overview
Dependencies
0
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.1.7 to 1.0.0

297

api.md
# Subset API
Subset export several basic and generalized set operations for JavaScript Arrays.
The generalized versions work best with the additionally supplied generalized equality and comparison functions.
This is in general a pure functional library, but a couple of functions does modify the input (`insert` and `delete` only). The generalized versions accept general notions of equality which is explored immediately below.
## Generalized Equality
This function is created primarily for the generalized set operations further down.
### $.equality(props..) :: (x, y -> x 'equality on props' y)
This is a special function that creates an equality testing function based on
properties to test on. It will return true if and only if all the properties listed
are the same for both x and y.
An equality function is a function that takes two elements and return whether or not they are equal. These can be constructed by lambdas in ES6, but two shorthands exist:
### $.equality(prop) :: (x, y) -> Boolean
This function creates an equality function based on a property name. It will return true if and only if the value of the property listed is the same for both x and y.
```js

@@ -17,7 +16,12 @@ var lenEquals = $.equality('length');

lenEquals([1,3,5], [2,4]); // false
```
var steve = {name: 'Steve', money: 30000, status: "Awesome"};
var peter = {name: 'Peter', money: 30000, status: "Depressed"};
var steve2 = {name: 'Clone', money: 30000, status: "Awesome"};
var equallyCool = $.equality('money', 'status');
### $.equalityBy(cost) :: (x, y) -> Boolean
This function creates an equality function based on a cost function. It will return true if and only if `cost(x) === cost(y)`.
```js
var steve = { name: 'Steve', money: 30000, rank: 5 };
var peter = { name: 'Peter', money: 30000, rank: 3 };
var steve2 = { name: 'Clone', money: 30000, rank: 5 };
var equallyCool = $.equalityBy((x) => x.money + '::' + x.status);
equallyCool(steve, peter); // false

@@ -27,16 +31,16 @@ equallyCool(steve, steve2); // true

In this case the check is actually comparing two strings with an arbitrary separator (and the value of money is stringified on each side).
This method of forcing string comparison works quite well in javascript, but if you find this practice barbaric, lambdas is your friend.
## Generalized Comparison
These functions help generate
[compare functions](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort)
for `Array.prototype.sort`.
A comparison function is a function that takes two elements and returns a a positive number if the first is greater, or a negative number if the first is smaller (or zero if no difference). These functions are typically passed to [Array.prototype.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort).
### $.compare([ord]) :: (x, y -> x `compare` y)
This creates a function which returns the numeric difference between x and y,
optionally multiplying by minus one if the ord parameter is set to `-1` for
descending order. The default ord parameter `+1` for ascending order may be omitted.
These are often created via lambdas in ES6, but a shorthands exist.
When passed to `Array.prototype.sort`, it will sort the array _numerically_
as opposed to the default ECMA behaviour of turning the elements into strings then
sorting them _lexicographically_. This helps avoid common sorting mistakes:
### $.compare([ord]) :: (x, y) -> Number
This creates a comparison function for numbers, or other types where `x.valueOf()` provides a sensible ordering.
When pased to `Array.prototype.sort`, it will sort the array _numerically_ as opposed to the default ECMA behaviour of turning the elements into strings, then sorting them _lexicographically_. This helps avoid common sorting mistakes:
```js

@@ -50,78 +54,56 @@ [1,4,3,2].sort(); // [1,2,3,4] (expected)

### $.compare(costFn [, ord]) :: (x, y -> cost(x) `compare` cost(y))
An overloaded variant of compare that takes a cost function to minimize (or any function that you may wish to maximize or minimize).
The ord parameter is there to optionally reverse the sort.
The extra `ord` parameter (similarly) defines what order you want values ordered in:
```js
[2, 100, 10, 4].sort($.compare(-1)); // [100, 10, 4, 2]
```
- `+1` : ascending on cost (x with lowest cost first)
- `-1` : descending on cost (x with highest cost first)
Note that you can override the `valueOf` method for a class to gain the ability to use `compare` with any type.
### $.compareBy(costFn [, ord]) :: (x, y) -> Number
An overloaded variant of compare that takes a cost function to minimize (or any function that you may wish to maximize or minimize).
```js
var cost = function (x) {
return 4*x.a + x.b;
};
var objs = [{a:1, b:0}, {a:0, b:3}]; // first has higher cost
objs.sort($.compare(cost)); // [{a:0, b:3}, {a:1, b:0}]
objs.sort($.compare(cost), +1); // [{a:0, b:3}, {a:1, b:0}]
objs.sort($.compare(cost), +1); // [{a:1, b:0}, {a:0, b:3}]
var cost = (x) => 4*x.a + x.b;
var objs = [ { a: 1, b: 0 }, { a: 0, b: 3 } ]; // first has higher cost
objs.sort($.compareBy(cost)); // [ { a: 0, b: 3 }, { a: 1, b: 0 } ]
objs.sort($.compareBy(cost, +1)); // [ { a: 0, b: 3 }, { a: 1, b: 0 } ]
objs.sort($.compareBy(cost, -1)); // [ { a: 1, b: 0 }, { a: 0, b: 3 } ]
```
The `ord` parameter can be used to optionally reverse the sort. Note that `compareBy` is equivalent to `compare` with the cost function `(x) => +x` (i.e. `valueOf`).
### $.comparing(prop [, ord [, ..]]) :: (x, y -> x 'compare props' y)
This creates a numeric compare function returning the numeric difference between
any (or: the) included property which is not zero.
If all properties are identical, it returns zero.
### $.comparing(prop [, ord]) :: (x, y) -> Number
A special case of `compareBy` that compares the values of a property.
Pass in the name(s) of a (numeric) property the
elements to be sorted all have, along with the direction of comparison for each
property: `+1` for ascending (default), `-1` for descending.
The default last ord parameter can be omitted, but it is recommended included.
For multiple property sort, the arguments go pairwise: prop1, ord1, prop2, ord2, ...
making the ord parameters are necessary.
```js
// compare index 1
[[1,3], [2,2],[3,4]].sort($.comparing(1)); // [ [2,2], [1,3], [3,4] ]
var users = [{ id: 1, money: 3 }, { id: 2, money: 0 }, { id: 3, money: 3 }];
users.sort($.comparing('money'));
// [ { id: 2, money: 0 }, { id: 1, money: 3 }, { id: 3, money: 3 } ]
```
var money = [{id: 1, money: 3}, {id: 2, money: 0}, {id: 3, money: 3}];
// sort by money asc. first, then id desc.
money.sort($.comparing('money', +1, 'id', -1));
For anything more advanced than this, you are better of writing a lambda that compares properties pairwise. Due to the nature of `||` in javascript you could actually write the following:
```js
var comparator = (x, y) => (x.money - y.money) || (y.id - x.id);
users.sort(comparator);
// [ { id: 2, money: 0 }, { id: 3, money: 3 }, { id: 1, money: 3 } ]
```
## Operations
In the following section, an argument named *cmp* denotes a comparison function
created by `comparing`, `compare`, or manually.
An argument named *eq* denotes an equality function created by `equality`, manually, or another module like `eq2` from [interlude](https://github.com/clux/interlude).
## Set Operations
The meat of the module.
### $.maximum(xs) :: Number
### $.minimum(xs) :: Number
### $.maximumBy(cmp, xs) :: xs[maxidx]
### $.minimumBy(cmp, xs) :: xs[minidx]
### $.indexOfBy(eq, xs, x) :: Number
A generalized version of `Array.prototype.indexOf` that takes a custom equality test.
If ordering is not based on a single numeric property, or you want the element
containing this property, then `$.maximumBy` is appropriate: Pass in a comparison
function and it will return the element which compares favorably against all
elements in `xs`.
To simply get the maximum return value of a property,
consider collecting up the values first then applying the faster `maximum` function.
Collecting first is going to be faster, but this implies loosing the association
between the original element.
```js
$.maximum([1,3,2,5]); // 5
var nested = [[1,3,2], [2], [2,3]];
$.maximum($.pluck('length', nested)); // 3
$.maximumBy($.comparing('length'), nested); // [ 1, 3, 2 ]
$.indexOfBy((x, y) => x.a === y.a, [ { a: 1 }, { a: 2 } ], { a: 1 }); // 0
$.indexOfBy((x, y) => x.a === y.a, [ { a: 1 }, { a: 2 } ], { a: 3 }); // -1
```
Note that unlike `$.maximum` which returns `-Infinity` in the case of an empty
Array, `$.maximumBy` returns `undefined` as this is the only thing possible
without knowing the structure of the elements in the array.
Similarly for `$.minimum` and `$.minimumBy`.
### $.intersect(xs, ys) :: zs
The 'intersect' function takes the intersection of two arrays.
For example,
The `intersect` function takes the intersection of two arrays.

@@ -138,38 +120,37 @@ ```js

It is a special case of 'intersectBy', which allows the programmer to
supply their own equality test.
It is a special case of `intersectBy` with generic equality (`===`) as the equality test.
### $.intersectBy(eq, xs, ys) :: zs
The non-overloaded version of `intersect`.
The generalized version of `intersect`.
```js
$.intersectBy($.equality('a'), [{a:1}, {a:4, b:0}], [{a:2}, {a:4, b:1}]);
$.intersectBy((x, y) => x.a === y.a, [{ a: 1 }, { a: 4, b: 0 }], [{ a: 2 }, { a: 4, b: 1 }]);
// [ { a: 4, b: 0 } ]
```
### $.nub(xs) :: ys
The nub function removes duplicate elements from an array.
In particular, it keeps only the first occurrence of each element.
(The name nub means _essence_.) It exploits the extra performance of `Array.prototype.indexOf` but would otherwise have been a special case of `nubBy`, which allows the programmer to supply their own equality test.
Note that elements from the first array is chosen if an element exists in the other that is equal.
### $.unique(xs) :: ys
The unique function removes duplicate elements from an array. In particular, it keeps only the first occurrence of each element.
```js
$.nub([1,3,2,4,1,2]); // [ 1, 3, 2, 4 ]
$.unique([1,3,2,4,1,2]); // [ 1, 3, 2, 4 ]
```
### $.nubBy(eq, xs) :: ys
The generalized version of `nub`.
It is a special case of `uniqueBy`, with generic equality (`===`) as the equality test.
### $.uniqueBy(eq, xs) :: ys
The generalized version of `unique`.
```js
var notCoprime = $($.gcd, $.gt(1));
var primes = $.nubBy(notCoprime, $.range(2, 11)); // [ 2, 3, 5, 7, 11 ]
var notCoprime = (x, y) => gcd(x, y) > 1;
var primes = $.uniqueBy(notCoprime, $.range(2, 11)); // [ 2, 3, 5, 7, 11 ]
```
Here the definition of equality is *a and b have common factors*.
Note the `range` and `$` functions from [interlude](https://github.com/clux/interlude).
Here the definition of equality is *a and b have common factors*, and later occurances with common factors are excluded.
Note the `range` from [interlude](https://github.com/clux/interlude).
### $.group(xs) :: ys
The group function takes an array and returns an array of arrays such that
the flattened result is equal to `xs`.
Moreover, each subarray is constructed by grouping the _consecutive_ equal elements
in `xs`. For example,
The group function takes an array and returns an array of arrays such that the flattened result is equal to `xs`.
Moreover, each subarray is constructed by grouping the _consecutive_ equal elements in `xs`. For example,

@@ -180,12 +161,10 @@ ```js

In particular, if `xs` is sorted, then the result is sorted
when comparing on the first sub element, i.e. `$.comparing(0)`.
It is a special case of groupBy, which allows the programmer to supply
their own equality test.
In particular, if `xs` is sorted, then the flattened result is sorted.
It is a special case of `groupBy`, with generic equality (`===`) as the equality test.
### $.groupBy(eq, xs) :: ys
The non-overloaded version of `group`.
The generalized version of `group`.
```js
$.groupBy($.equality('a'), [{a:1}, {a:4, b:1}, {a:4, b:0}, {a:1}]);
$.groupBy((x,y) => x.a === y.a, [{ a : 1 }, { a: 4, b: 1 }, { a: 4, b: 0 }, { a: 1 }]);
// [ [ { a: 1 } ],

@@ -205,10 +184,9 @@ // [ { a: 4, b: 1 }, { a: 4, b: 0 } ],

but if the first array contains duplicates, so will the result.
It is a special case of unionBy, which allows the programmer to supply
their own equality test.
It is a special case of `unionBy`, with generic equality (`===`) as the equality test.
### $.unionBy(eq, xs, ys) :: zs
The non-overloaded version of `union`.
The generalized version of `union`.
```js
$.unionBy($.equality('a'), [{a:1},{a:3}], [{a:2},{a:3}]);
$.unionBy((x,y) => x.a === y.a, [{ a: 1 }, { a: 3 }], [{ a: 2 }, { a: 3 }]);
// [ { a: 1 }, { a: 3 }, { a: 2 } ]

@@ -218,9 +196,6 @@ ```

### $.difference(xs, ys) :: zs
Returns the difference between xs and ys; xs \ ys.
The first occurrence of each element of ys in turn (if any) has been
removed from xs. Thus `$.difference(ys.concat(xs), ys) equals xs`.
Returns the difference between `xs` and `ys`, in set notation: `xs \ ys`.
The first occurrence of each element of `ys` in turn (if any) has been
removed from `xs`. Thus `$.difference(ys.concat(xs), ys)` equals `xs` (in the `deepEqual` sense).
It is a special case of differenceBy, which allows the programmer to supply
their own equality test.
```js

@@ -230,7 +205,9 @@ $.difference([1,2,2,3], [2,3,4]); // [ 1, 2 ]

It is a special case of `differenceBy`, with generic equality (`===`) as the equality test.
### $.differenceBy(eq, xs, ys) :: zs
The non-overloaded version of `difference`.
The generalized version of `difference`.
```js
$.differenceBy($.equality('a'), [{a:1}, {a:2}], [{a:2}, {a:3}]);
$.differenceBy((x,y) => x.a === y.a, [{ a: 1 }, { a: 2 }], [{ a: 2 }, { a: 3 }]);
// [ { a: 1 } ]

@@ -240,28 +217,22 @@ ```

### $.insert(xs, x) :: xs
The insert function takes an element and an array and inserts the element
into the array at the last position where it is still less than or equal
to the next element. In particular, if the array is sorted before the call,
the result will also be sorted.
The insert function takes an element `x` and an array `xs` and inserts the element into the array at the last position where it is still less than or equal
to the next element. In particular, if the array is sorted before the call, the result will also be sorted.
It is a special case of `insertBy`,
which allows the programmer to supply their own comparison function.
```
$.insert([1,2,3,4], 3)
```js
$.insert([1,2,3,4], 3);
[ 1, 2, 3, 3, 4 ]
```
It is a special case of `insertBy`, with generic numeric ordering as the comparator.
### $.insertBy(cmp, xs, x) :: xs
The non-overloaded version of `insert`.
The generalized version of `insert`.
```js
$.insertBy($.comparing('a'), [{a:1}, {a:2}, {a:3}], {a:3, n:1})
// [ { a: 1 },
// { a: 2 },
// { a: 3, n: 1 },
// { a: 3 } ]
$.insertBy($.comparing('a'), [{ a: 1 }, { a: 2 }, { a: 3 }], { a: 3, n: 1 });
// [ { a: 1 }, { a: 2 }, { a: 3, n: 1 }, { a: 3 } ]
```
### $.delete(xs, x) :: xs
Removes the first occurrence of `x` from its array argument `xs`.
Removes the *first* occurrence of `x` from its array argument `xs`.

@@ -272,5 +243,3 @@ ```js

Behaviourally equivalent to the generalized
version `deleteBy` with `$.eq2` as the supplied equality test, but
this special case implementation uses `Array.prototype.indexOf` and is faster.
It is a special case of `deleteBy`, with generic equality (`===`) as the equality test.

@@ -281,3 +250,3 @@ ### $.deleteBy(eq, xs, x) :: xs

```js
$.deleteBy($.equality('a'), [{a:1},{a:2},{a:3},{a:2}], {a:2})
$.deleteBy((x,y) => x.a === y.a, [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 2 }], { a: 2 });
// [ { a: 1 }, { a: 3 }, { a: 2 } ]

@@ -287,4 +256,3 @@ ```

#### Warning: delete/insert modifies
For efficiency; `delete`, `insert`, `deleteBy`, `insertBy` all modify the
passed in array. To return an independent result, modify a shallow copy instead:
To maintain javascript conventions; `delete`, `insert`, `deleteBy`, `insertBy` all modify the passed in array. To return an independent result, pass in a copy instead:

@@ -301,3 +269,5 @@ ```js

#### NB2: delete/difference only removes one per request
Note that `slice` provides a *shallow* copy (objects and arrays inside an array are copied by reference), but this is sufficient for an array of numbers.
#### Warning: delete/difference only removes one per request
The delete functions only remove the first instance.

@@ -308,28 +278,61 @@ To delete all, `Array.prototype.filter` is best suited:

var xs = [1,2,2,3,4];
xs.filter($.notElem([2,3])); // [ 1, 4 ]
xs.filter((x) => [2,3].indexOf(x) < 0); // [ 1, 4 ]
$.difference(xs, [2,3]); // [ 1, 2, 4 ]
xs.filter($.neq(2)); // [ 1, 3, 4 ]
xs.filter((x) => x !== 2); // [ 1, 3, 4 ]
$.delete(xs, 2); // [ 1, 2, 3, 4 ]
```
Here `notElem`, and `neq` are simple functions from [interlude](https://github.com/clux/interlude).
## Extras
Max/min helpers and generalized versions are provided.
### $.maximum(xs) :: Number
### $.minimum(xs) :: Number
These functions are simple wrapper around `Math.max` and `Math.min`
```js
$.maximum([1,3,2,5]); // 5
$.minimum([]); // Infinity
```
### $.isSubsetOf(xs, ys [, proper]) :: Boolean
Checks if `xs` is a subset of `ys`, and optionally, if it is a proper subset.
### $.maximumBy(cmp, xs) :: Maximal x
### $.minimumBy(cmp, xs) :: Minimal x
For picking maximal values not based on numeric value, or if you simply want the element containing the maximal value of a property (say), then these functions are appropriate.
```js
var nested = [[1,3,2], [2], [2,3]];
$.maximum(nested.map((x) => x.length)); // 3
$.maximumBy($.comparing('length'), nested); // [ 1, 3, 2 ]
```
Note that unlike `maximum` which returns `-Infinity` in the case of an empty
Array, `maximumBy` has nothing sensible to return since the structure of the type passed in is unknown.
```js
$.minimumBy($.comparing('something'), []); // undefined
```
### $.isSubsetOf(xs, ys) :: Boolean
Checks if `xs` is a subset of `ys`.
```js
$.isSubsetOf([1,2], [1,2,3]); // true
$.isSubsetOf([1,2,3], [1,2]); // false
$.isSubsetOf([1,2,3], [1,2,3]); // true
$.isSubsetOf([1,2,3], [1,2,3], true); // false (not proper subset)
$.isSubsetOf([1,2,3], [1,2,3]); // true (but not a proper subset)
```
Note that duplicates count as a separate element, so if you want true set behaviour, ensure that everything passed satisfies `x === $.nub(x)` by either calling it explicitly or modelling it well.
### $.isProperSubsetOf(xs, ys) :: Boolean
Checks if `xs` is a *strict* suset of `ys`.
```js
$.isSubsetOf([1,2,2], [1,2,3]); // false
$.isSubsetOf([1,2,2], [1,2,2,3]); // true
$.isSubsetOf($.nub([1,2,2]), [1,2,3]); // true
$.isProperSubsetOf([1,2], [1,2,3]); // true
$.isProperSubsetOf([1,2,3], [1,2]); // false
$.isProperSubsetOf([1,2,3], [1,2,3]); // false
```
#### NB: isSubset functions assume no duplicates
For this reason you will see:
- `[1,2,2]` is counted as a subset of `[1,2]`
- `[1,2]` is not a proper subset of `[1,2,2]`
So think of all arguments to these functions as equivalent to being wrapped in `unique`.

@@ -0,1 +1,14 @@

1.0.0 / 2016-01-27
==================
* Rewrite for ES6
* `indexOfBy` added to exports
* `isSubsetOf` now assumes inputs have no duplicates
* `isSubsetOf` third boolean arg to check if proper subset no longer exists
* `isProperSubsetOf` now exported - and assumes no duplicates
* `compare` now split into `compare` and `compareBy`
* `comparing` (variadic version of `compare`) removed
* `equality` now only takes single argument
* `equalityBy` added to exports
* `nub` and `nubBy` renamed to `unique` and `uniqueBy`
0.1.7 / 2015-11-15

@@ -2,0 +15,0 @@ ==================

@@ -5,3 +5,3 @@ {

"description": "Generalized set operations and comparisons in the style of Haskell",
"version": "0.1.7",
"version": "1.0.0",
"repository": {

@@ -23,15 +23,16 @@ "type": "git",

"Ord",
"ES5"
"ES6"
],
"main": "subset.js",
"scripts": {
"test": "nodeunit --reporter=verbose test/*.js",
"coverage": "jscoverage subset.js && SUBSET_COV=1 nodeunit --reporter=lcov test"
"test": "bndg test/*.js",
"precoverage": "istanbul cover bndg test/*.js",
"coverage": "cat coverage/lcov.info && rm -rf coverage"
},
"dependencies": {},
"devDependencies": {
"nodeunit": "~0.9.0",
"jscoverage": "~0.5.4"
"bandage": "^0.4.2",
"istanbul": "^0.4.2"
},
"license": "MIT"
}

@@ -8,35 +8,28 @@ # Subset

Subset provides basic and generalized set operations for JavaScript.
They are inspired by a subset of the interface to Haskell's [Data.List](http://www.haskell.org/ghc/docs/latest/html/libraries/base/Data-List.html), but optimized for JavaScript semantics and performance.
They are inspired by a subset of the interface to Haskell's [Data.List](https://hackage.haskell.org/package/base/docs/Data-List.html), but optimized for JavaScript semantics.
The new ES6 `Set` class is not particularly helpful for doing set operations on general objects (as their only version of equality is `===`), and this module provides a general alternative for people who want to do the same-ish things on arrays.
## Usage
Attach it to the short variable of choice:
Use it with qualified imports with the yet unfinished module `import` syntax or attach it to the short variable of choice. For selling points, here's how it will look with ES7 modules.
```javascript
var $ = require('subset');
```
```js
import { equality, union, unionBy, intersect, unique, uniqueBy, insert, delete, group } from 'autonomy'
and fire up the set engine:
intersect([1,2,3,4], [2,4,6,8]); // [ 2, 4 ]
```javascript
$.union([1,3,5], [4,5,6]); // [ 1, 3, 5, 4, 6 ]
$.unionBy($.equality('a'), [{a:1},{a:3}], [{a:2},{a:3}]);
union([1,3,5], [4,5,6]); // [ 1, 3, 5, 4, 6 ]
unionBy(equality('a'), [{ a: 1 }, { a: 3 }], [{ a: 2 }, { a: 3 }]);
// [ { a: 1 }, { a: 3 }, { a: 2 } ]
$.intersect([1,2,3,4], [2,4,6,8]); // [ 2, 4 ]
unique([1,3,2,4,1,2]); // [ 1, 3, 2, 4 ]
$.nub([1,3,2,4,1,2]); // [ 1, 3, 2, 4 ]
var notCoprime = (x, y) => gcd(x, y) > 1;
var primes = $.uniqueBy(notCoprime, $.range(2, 11)); // [ 2, 3, 5, 7, 11 ]
$.group([1,2,2,3,5,5,2]); // [ [1], [2,2], [3], [5,5], [2] ]
group([1,2,2,3,5,5,2]); // [ [1], [2,2], [3], [5,5], [2] ]
$.insert([1,2,3,4], 3); // [ 1, 2, 3, 3, 4 ]
insert([1,2,3,4], 3); // [ 1, 2, 3, 3, 4 ]
$.delete([1,2,3,2,3], 2); // [ 1, 3, 2, 3 ]
var nested = [[1,3,2], [2], [2,3]];
$.maximumBy($.comparing('length'), nested); // [ 1, 3, 2 ]
nested.sort($.comparing('length')); // [ [ 2 ], [ 2, 3 ], [ 1, 3, 2 ] ]
[2, 100, 10, 4].sort(); // [10, 100, 2, 4] <- default lexicographical order
[2, 100, 10, 4].sort($.compare()); // [2, 4, 10, 100] <- sensible numerical order
delete([1,2,3,2,3], 2); // [ 1, 3, 2, 3 ]
```

@@ -46,6 +39,5 @@

Note that it is often useful to get it with the larger utility library:
[interlude](https://github.com/clux/interlude) for which it was made.
Note that it is often useful to get it with the larger utility library [interlude](https://github.com/clux/interlude) for which it was made.
## License
MIT-Licensed. See LICENSE file for details.

@@ -7,77 +7,41 @@ var $ = {};

$.equality = function () {
var pargs = arguments;
return function (x, y) {
for (var i = 0, len = pargs.length; i < len; i += 1) {
if (x[pargs[i]] !== y[pargs[i]]) {
return false;
}
}
return true;
};
};
var eq2 = (x, y) => x === y; // used throughout
$.equality = (prop) => (x, y) => x[prop] === y[prop];
$.equalityBy = (cost) => (x, y) => cost(x) === cost(y);
$.compare = (c) => (x, y) => (c || 1)*(x - y);
$.compareBy = (cost, c) => (x, y) => (c || 1)*(cost(x) - cost(y));
$.comparing = (prop, c) => (x, y) => (c || 1)*(x[prop] - y[prop]);
$.compare = function (c, c2) {
if (typeof c === 'function') {
c2 = c2 || 1;
return function (x, y) {
return c2 * (c(x) - c(y));
};
}
c = c || 1;
return function (x, y) {
return c * (x - y);
};
};
// ---------------------------------------------
// Max/min + subset checks
// ---------------------------------------------
// result of this can be passed directly to Array::sort
$.comparing = function () {
var args = arguments;
return function (x, y) {
for (var i = 0, len = args.length; i < len; i += 2) {
var factor = args[i + 1] || 1;
if (x[args[i]] !== y[args[i]]) {
return factor * (x[args[i]] - y[args[i]]);
}
}
return 0;
};
};
// max/min
$.maximum = (xs) => Math.max.apply(Math, xs);
$.minimum = (xs) => Math.min.apply(Math, xs);
// default equality, like `operators` eq2
var eq2 = function (x, y) {
return x === y;
// generalized max/min - cannot be called on an empty array
$.maximumBy = (cmp, xs) => xs.reduce((max, x) => cmp(x, max) > 0 ? x : max, xs[0]);
$.minimumBy = (cmp, xs) => xs.reduce((min, x) => cmp(x, min) < 0 ? x : min, xs[0]);
// subset checks - does not account for duplicate elements in xs or ys
$.isSubsetOf = (xs, ys) => xs.every((x) => ys.indexOf(x) >= 0);
$.isProperSubsetOf = function (xs, ys) {
return $.isSubsetOf(xs, ys) && ys.some((y) => xs.indexOf(y) < 0);
};
// ---------------------------------------------
// Operations
// Set Operations
// ---------------------------------------------
// max/min + generalized
$.maximum = function (xs) {
return Math.max.apply(Math, xs);
};
$.minimum = function (xs) {
return Math.min.apply(Math, xs);
};
$.maximumBy = function (cmp, xs) {
for (var i = 1, max = xs[0], len = xs.length; i < len; i += 1) {
if (cmp(xs[i], max) > 0) {
max = xs[i];
// generalized indexOf
$.indexOfBy = function (eq, xs, x) {
for (var i = 0, len = xs.length; i < len; i += 1) {
if (eq(xs[i], x)) {
return i;
}
}
return max;
return -1;
};
$.minimumBy = function (cmp, xs) {
for (var i = 1, min = xs[0], len = xs.length; i < len; i += 1) {
if (cmp(xs[i], min) < 0) {
min = xs[i];
}
}
return min;
};
// Modifying Array operations

@@ -94,19 +58,6 @@ $.insertBy = function (cmp, xs, x) {

};
$.insert = (xs, x) => $.insertBy($.compare(), xs, x);
$.insert = function (xs, x) {
return $.insertBy($.compare(), xs, x);
};
$.deleteBy = function (eq, xs, x) {
for (var i = 0, len = xs.length; i < len; i += 1) {
if (eq(xs[i], x)) {
xs.splice(i, 1);
return xs;
}
}
return xs;
};
$.delete = function (xs, x) {
var idx = xs.indexOf(x);
var idx = $.indexOfBy(eq, xs, x);
if (idx >= 0) {

@@ -117,104 +68,44 @@ xs.splice(idx, 1);

};
$.delete = (xs, x) => $.deleteBy(eq2, xs, x);
// "Set" operations
// Pure operations
$.intersectBy = function (eq, xs, ys) {
var result = []
, xLen = xs.length
, yLen = ys.length;
if (xLen && yLen) {
for (var i = 0; i < xLen; i += 1) {
var x = xs[i];
for (var j = 0; j < yLen; j += 1) {
if (eq(x, ys[j])) {
result.push(x);
break;
}
}
return xs.reduce((acc, x) => {
if ($.indexOfBy(eq, ys, x) >= 0) {
acc.push(x);
}
}
return result;
return acc;
}, []);
};
$.intersect = (xs, ys) => $.intersectBy(eq2, xs, ys);
$.intersect = function (xs, ys) {
return $.intersectBy(eq2, xs, ys);
};
$.nubBy = function (eq, xs) {
var result = [];
for (var i = 0, len = xs.length; i < len; i += 1) {
var keep = true;
for (var j = 0, resLen = result.length; j < resLen; j += 1) {
if (eq(result[j], xs[i])) {
keep = false;
break;
}
$.uniqueBy = function (eq, xs) {
return xs.reduce((acc, x) => {
if ($.indexOfBy(eq, acc, x) < 0) {
acc.push(x);
}
if (keep) {
result.push(xs[i]);
}
}
return result;
return acc;
}, []);
};
$.unique = (xs) => $.uniqueBy(eq2, xs);
// nub, build up a list of unique (w.r.t. equality)
// elements by checking if current is not 'equal' to anything in the buildup
// http://jsperf.com/nubnubbytest1 => indexOf clearly beats calling $.nubBy(eq2)
$.nub = function (xs) {
$.groupBy = function (eq, xs) {
var result = [];
for (var i = 0, len = xs.length; i < len; i += 1) {
if (result.indexOf(xs[i]) < 0) {
result.push(xs[i]);
}
for (var i = 0, j = 0, len = xs.length; i < len; i = j) {
for (j = i + 1; j < len && eq(xs[i], xs[j]);) { j += 1; }
result.push(xs.slice(i, j));
}
return result;
};
$.group = (xs) => $.groupBy(eq2, xs);
$.groupBy = function (eq, xs) {
var result = []
, j, sub;
for (var i = 0, len = xs.length; i < len; i = j) {
sub = [xs[i]];
for (j = i + 1; j < len && eq(xs[i], xs[j]); j += 1) {
sub.push(xs[j]);
}
result.push(sub);
}
return result;
};
$.group = function (xs) {
return $.groupBy(eq2, xs);
};
$.unionBy = function (eq, xs, ys) {
return xs.concat(xs.reduce($.deleteBy.bind(null, eq), $.nubBy(eq, ys)));
return xs.concat(xs.reduce($.deleteBy.bind(null, eq), $.uniqueBy(eq, ys)));
};
$.union = (xs, ys) => xs.concat(xs.reduce($.delete, $.unique(ys)));
$.union = function (xs, ys) {
return xs.concat(xs.reduce($.delete, $.nub(ys)));
};
$.differenceBy = (eq, xs, ys) => ys.reduce($.deleteBy.bind(null, eq), xs.slice());
$.difference = (xs, ys) => ys.reduce($.delete, xs.slice());
$.differenceBy = function (eq, xs, ys) {
return ys.reduce($.deleteBy.bind(null, eq), xs.slice()); // reduce a copy
};
$.difference = function (xs, ys) {
return ys.reduce($.delete, xs.slice());
};
$.isSubsetOf = function (xs, ys, proper) {
var parent = ys.slice();
for (var i = 0; i < xs.length; i += 1) {
var x = xs[i]
, idx = parent.indexOf(x);
if (idx < 0) {
return false;
}
parent.splice(idx, 1);
}
return (proper) ? (parent.length > 0) : true;
};
// end - export
module.exports = $;
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc