Contents
Array.prototype.indexOf()
Extend Array.prototype.indexOf
to take a callback.
1
2
3
4
5
6
7
8
9
10
11
12
| > [ 1, 3, 5, 6, 7 ].indexOf(8)
-1
> [ 1, 3, 5, 6, 7 ].indexOf(v => v > 7)
-1
> [ 1, 3, 5, 6, 7 ].indexOf(1)
0
> [ 1, 3, 5, 6, 7, 1 ].indexOf(1, 2)
5
> [ 1, 3, 5, 6, 7, 8 ].indexOf(v => v % 2 === 0)
3
> [ 1, 3, 5, 6, 7, 8 ].indexOf(v => v % 2 === 0, 4)
5
|
1
2
3
4
5
6
7
8
9
10
11
12
| Array.prototype.indexOf = function(x, fromIndex=0) {
const _x = this.slice(fromIndex);
for (let idx in _x) {
idx = parseInt(idx, 10);
const val = _x[idx];
const found = idx + fromIndex;
if ((typeof(x) === 'function' && x(val)) || val === x) {
return found;
}
}
return -1;
};
|
chunkarr()
Chunk an array.
1
2
| > chunkArr([1, 2, 3, 4, 5, 6], 3)
[ [ 1, 2, 3 ], [ 4, 5, 6 ] ]
|
1
2
3
4
5
6
7
| const chunkArr = function(arr, size) {
chunked = [];
while (arr.length > 0) {
chunked.push(arr.splice(0, size));
}
return chunked;
};
|
cmpArr()
Compare arrays whose elements are primitive values.
1
2
3
4
5
6
| > cmpArr([1, 2, 3], [1, 2])
false
> cmpArr([1, 2, 3], [3, 2, 1])
false
> cmpArr([1, 2, 3], [1, 2, 3])
true
|
1
2
3
4
5
6
7
8
9
| const cmpArr = function(arr1, arr2) {
if (arr1.length !== arr2.length) return false;
for (let idx in arr1) {
if (arr1[idx] !== arr2[idx]) {
return false;
}
}
return true;
};
|
cmpStr()
Compare two string property values case-insensitively.
1
2
3
4
| > cmpStr({'a': 'b'}, {'a': 'c'}, 'a')
-1
> cmpStr({'a': 'b'}, {'a': 'B'}, 'a')
0
|
1
2
| const cmpStr = (obj1, obj2, val) =>
obj1[val].toLowerCase().localeCompare(obj2[val].toLowerCase());
|
count()
Count occurrences of elt
in seq
.
1
2
3
4
| > count(['a', 'a', 'b', 'c'], 'a')
2
> count('foobar', 'o')
2
|
elt
can also be a function:
1
2
| > count(['a', 'a', 'b', 'c'], x => x === 'a')
2
|
1
2
3
4
5
6
| const count = function(seq, elt) {
const s = typeof seq === 'string' ? [...seq] : seq.slice();
return s.filter(x =>
typeof elt === 'function' ? elt(x) : x === elt
).length
};
|
domainName()
Return domain name.
1
2
3
4
5
6
7
8
9
10
| > domainName("http://google.com")
'google'
> domainName("http://google.co.jp")
'google'
> domainName("www.xakep.ru")
'xakep'
> domainName("xakep.ru")
'xakep'
> domainName("http://www.xakep.ru")
'xakep'
|
1
2
3
4
| const domainName = s =>
s.replace(/http[s]*:\/\//, '')
.replace('www.', '')
.split(/\/\/|\./)[0];
|
eltFreq()
Return an object holding frequency counts of array elements.
1
2
| > eltFreq(['a', 'a', 'b', 'c'])
{ 'a': 2, 'b': 1, 'c': 1 }
|
1
2
3
4
5
| const eltFreq = arr =>
arr.reduce((freq, n) => {
freq[n] = freq[n] + 1 || 1;
return freq;
}, {});
|
fan()
‘Fan’ or unfurl characters in a sequence.
1
2
3
4
5
| > fan('foo') // string
[ 'f', 'fo', 'foo' ]
//
> fan(123) // number
[ '1', '12', '123' ]
|
1
2
| const fan = x =>
[...String(x)].map((curr, idx) => String(x).slice(0, idx + 1));
|
idxs()
Extract characters at specified index positions and construct a
new sequence. If index is out of range, use empty string.
1
2
| > idxs([1, 2, 6, 7], 'foobarbarous')
'ooba'
|
1
2
| const idxs = (arr, s) =>
arr.map(elt => s[elt] || '').join('');
|
includesSeq()
Return true if arr
contains sequence seq
.
Expects seq
to be at least two characters.
1
2
3
4
5
| const includesSeq = (arr, seq) =>
arr.length &&
2 <= seq.length &&
seq.reduce((prev, curr) => prev &&
arr.indexOf(curr) > arr.indexOf(prev));
|
innerSort()
Sort by a primary element and then by a secondary element.
1
2
3
4
| > const data = [{'a': 'y', 'b': 'x'}, {'a': 'x', 'b': 'z'}, {'a': 'x', 'b': 'y'}]
> const compare = (a, b, x) => a[x].localeCompare(b[x])
> innerSort(data, compare, 'a', 'b')
[{a: 'x', b: 'y'}, {a: 'x', b: 'z'}, {a: 'y', b: 'x'}]
|
1
2
3
4
| const innerSort = (arr, f, x, y) =>
arr.sort((a, b) => f(a, b, x))
.sort((a, b) => f(a, b, x) ||
f(a, b, y));
|
isVowelAscEng()
Return true if c
is an ASCII English vowel character.
1
2
3
4
| > isVowelAscEng('a')
true
> isVowelAscEng('b')
false
|
1
2
3
| const vowelAscEng = "aeiouAEIOU";
const isVowelAscEng = c => !!c && vowelAscEng.includes(c);
|
last()
Return last element of arr
.
1
2
| > last([[0, 1], [1, 2], [3, 4]])
[ [ 3, 4 ] ]
|
1
| const last = arr => arr.slice(-1);
|
listify()
Listify array of strings, including optional serial comma.
1
2
3
4
5
6
| > listify('a')
a
> listify(['a', 'b', 'c'], true)
a, b, and c
> listify(['a', 'b', 'c'], false)
a, b and c
|
1
2
3
4
5
6
7
| const listify = (arr, serial) =>
arr.length === 1
? arr[0]
: arr.slice(0, -1)
.join(', ') +
(serial ? ',' : '') +
` and ${arr.slice(-1)}`;
|
mirror()
Mirror an object.
1
2
| > mirror({'Z': 'A', 'Y': 'B'})
{ A: 'Z', B: 'Y' }
|
1
2
3
4
5
| const mirror = obj =>
Object.keys(obj).reduce((acc, curr) => {
acc[obj[curr]] = curr;
return acc;
}, {});
|
mults()
Yield multiples of n
up to max
, non-inclusive.
1
2
| > [...mul(2, 9)]
[ 2, 4, 6, 8 ]
|
1
2
3
4
5
6
7
| function* mults(n, max) {
let i = 1, _next = n;
while (_next < max) {
yield _next;
_next = n * ++i;
}
}
|
nextMinGreater()
Get the next smallest greater number following the
number at arr[idx]
.
1
2
| > nextMinGreater([1, 2, 1, 3, 2], 2)
2
|
1
2
3
4
5
| const nextMinGreater = function(arr, idx) {
let rest = arr.slice(idx + 1);
rest = rest.filter(elt => elt > arr[idx]);
return rest.length ? Math.min(...rest) : -1;
}
|
nonConsec()
Return an array of numeric values in arr
that do not follow
consecutively from preceding numeric values.
1
2
| > nonConsec([1, 2, 3, 4, 6, 7, 9])
[ 6, 9 ]
|
1
2
3
| const nonConsec = arr =>
arr.filter((elt, idx, arr) =>
elt - arr[idx - 1] > 1);
|
nonUniq()
Return all non-unique values of arr
.
1
2
| > nonUniq(['a', 'a', 'b', 'b', 'c'])
[ 'a', 'a', 'b', 'b' ]
|
1
| const nonUniq = arr => arr.filter(elt => count(arr, elt) > 1);
|
nth()
Return n
th element of arr
(zero-indexed).
1
2
| > nth(['a', 'b', 'c'], 1)
[ 'b' ]
|
1
2
3
4
| const nth = (arr, n) =>
n === -1
? last(arr)
: arr.slice(n, n + 1);
|
obj2arr()
Return an array corresponding to frequency of occurrence
tabulated in the input object.
1
2
| > obj2arr({'a': 2, 'b': 3})
[ 'a', 'a', 'b', 'b', 'b' ]
|
1
2
3
4
5
6
7
| const obj2arr = obj =>
Object.keys(obj)
.reduce((acc, key) => {
acc.push(...Array.from(Array(obj[key]))
.map(elt => (/\d/).test(key) ? parseInt(key) : key));
return acc;
}, []);
|
Object.values()
Polyfill for ES2017 draft Object.values().
Return an array containing the values in obj
.
1
2
| > Object.values({'a': 1, 'b': 2, 'c': 3})
[ 1, 2, 3 ]
|
1
2
3
4
5
6
7
| Object.prototype.values = function(obj) {
const result = [];
for (const k of Object.keys(obj)) {
result.push(obj[k]);
}
return result;
};
|
randInt()
Return pseudo-random integer in range min
, max
(non-inclusive).
1
2
3
4
| > randInt(0,3)
0
> randInt(0,3)
2
|
1
| const randInt = (min, max) => Math.floor(Math.random() * max) + min;
|
range()
Return range from begin
to end
(inclusive).
1
2
3
4
5
6
7
8
| > Array.from(range(0, 3))
[ 0, 1, 2, 3 ]
> Array.from(range(0, 6, 2))
[ 0, 2, 4, 6 ]
> Array.from(range(3, 0))
[ 3, 2, 1, 0 ]
> Array.from(range(6, 0, 2))
[ 6, 4, 2, 0 ]
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| function* range(begin, end, step=1) {
if (begin <= end) {
while (begin <= end) {
yield begin;
begin += step;
}
} else {
while (begin >= end) {
yield begin;
begin -= step;
}
}
}
|
rangeBitCount()
Count occurrences of 1
in binary representations of all integers
in range a
to b
inclusive.
1
2
| > rangeBitCount(2, 7)
11
|
1
2
3
4
5
6
7
| const rangeBitCount = function(a, b) {
let r = [];
let g = range(a, ++b);
while (b--) r.push(g.next().value);
let s = r.map(elt => elt ? elt.toString(2) : '').join('');
return count(s.split(''), '1');
};
|
reversed()
Given a string s
, return a string with the characters in s
reversed. Given an array a
, return an array with the elements
in a
reversed. Given a number n
, return a number with the
digits in n
reversed.
1
2
3
4
5
6
| > reversed('foobar')
'raboof'
> reversed(32243)
34223
> reversed(['a', 'b', 'c'])
[ 'c', 'b', 'a' ]
|
1
2
3
4
5
6
| const reversed = x =>
typeof x === 'number'
? Number([...x.toString()].reverse().join(''))
: typeof x === 'string'
? [...x].reverse().join('')
: x.reverse();
|
runningAverage()
Return a running average.
1
2
3
4
5
6
7
8
| > const rAvg = runningAverage()
undefined
> rAvg(1)
1
> rAvg(5)
3
> rAvg(10)
5.33
|
1
2
3
4
5
6
7
8
| const runningAverage = () => {
let count = total = 0;
return n => {
total += n;
count++;
return Number((total / count).toFixed(2));
};
};
|
shiftNmg()
Replace every element of arr
with the next smallest
greater number following it, or -1
if none is found.
1
2
| > shiftNmg([1, 2, 3])
[ 2, 3, -1 ]
|
1
2
3
| const shiftNmg = arr =>
arr.map((elt, idx) =>
nextMinGreater(arr, idx));
|
shuffle()
Shuffle an array.
Does not compare arr
to return value, so no guarantees.
1
2
| > shuffle([1, 2, 3, 4, 5])
[ 2, 1, 3, 4, 5 ]
|
1
2
3
4
| const shuffle = function(arr) {
let _arr = arr.slice();
return arr.map(elt => _arr.splice(randInt(0, _arr.length), 1)[0]);
};
|
shuffleInner()
Shuffle inner array (elements at indexes 1 through -2).
1
2
| > shuffleInner([1, 2, 3, 4, 5])
[ 1, 4, 2, 3, 5 ]
|
1
2
3
4
| const shuffleInner = arr =>
arr.slice(0, 1)
.concat(shuffle(arr.slice(1, -1)))
.concat(arr.slice(-1));
|
smash()
Smash all whitespace.
1
2
| > smash(' foo bar b a z ')
'foobarbaz'
|
1
2
| const smash = s =>
s.replace(/\s/g, '');
|
sortedn()
Sort an array of numeric values.
Array.prototype.sort()
uses Unicode point order:
1
2
| > [1, 10, 21, 2].sort()
[ 1, 10, 2, 21 ] // <= oops
|
Compare:
1
2
| > sortedn([1, 10, 21, 2])
[ 1, 2, 10, 21 ]
|
1
2
| const sortedn = arr =>
arr.sort((a, b) => a - b);
|
strCompl()
Swap each symbol in a string with its complement.
1
2
3
| > const compls = {'A': 'T', 'C': 'G'}
> strCompl('ATTGC', compls)
'TAACG'
|
1
2
3
4
| const strCompl = (str, compls) =>
[...str]
.map(char => compls[char] || mirror(compls)[char])
.join('');
|
sum()
Sum arguments or array.
1
2
3
4
| > sum(1, 2, 3)
6
> sum([1, 2, 3])
6
|
1
2
3
4
5
6
| const sum = function(seq) {
const add = (a, b) => a + b;
return Array.isArray(seq)
? seq.reduce(add)
: [...arguments].reduce(add);
};
|
toUpperSubs()
Convert a substring to uppercase.
1
2
| > toUpperSubs('foobar', 2, 4)
'foOBar'
|
1
2
3
4
| const toUpperSubs = (s, begin, end) =>
s.substring(0, begin) +
s.substring(begin, end).toUpperCase() +
s.substring(end);
|
uniq()
Return non-unique element of arr
.
Takes optional function proc
.
Assumes only one non-unique element.
1
2
| > uniq(['a', 'a', 'b', 'c', 'd'])
'b'
|
Some helper functions:
1
2
3
4
5
6
7
8
9
10
11
| > const smash = s => s.replace(/\s/g, '')
> smash('Foo Bar Baz')
'FooBarBaz'
> const setify = s => new Set([...smash(s).toLowerCase()])
> setify('Foo Bar Baz')
Set { 'f', 'o', 'b', 'a', 'r', 'z' }
> const proc = s => Array.from(setify(s)).sort().join('')
> proc('foo bar baz')
'abforz'
|
Invoke with function:
1
2
3
4
5
| > uniq(['Anagram',
'Internet Anagram Server',
'I Rearrangement Servant'
], proc)
'Anagram'
|
1
2
3
4
5
6
7
8
| const uniq = (arr, proc = x => x) => {
let nonUniq = arr[0];
for (let elt of arr.slice(1)) {
if (proc(nonUniq) === proc(elt)) break;
else nonUniq = elt;
}
return arr.filter(elt => proc(elt) !== proc(nonUniq))[0];
};
|
ys()
Return y-values of an array of [x, y]
arrays.
1
2
| > ys([[0, 1], [1, 2], [2, 3]])
[ 1, 2, 3 ]
|
1
| const ys = arr => arr.map(xy => xy[1]);
|