# JavaScript30秒， 从入门到放弃之Array（五）

2018-02-11 14:10:03来源:segmentfault作者:supermao人点击

sampleSize

Gets n random elements at unique keys from array up to the size of array.

Shuffle the array using the Fisher-Yates algorithm. Use Array.slice() to get the first n elements. Omit the second argument, n to get only one element at random from the array.

const sampleSize = ([...arr], n = 1) => {
let m = arr.length;
while (m) {
const i = Math.floor(Math.random() * m--);
[arr[m], arr[i]] = [arr[i], arr[m]];
}
return arr.slice(0, n);
};

➜code cat sampleSize.js
const sampleSize = ([...arr], n = 1) => {
let m = arr.length;
while (m) {
const i = Math.floor(Math.random() * m--);
[arr[m], arr[i]] = [arr[i], arr[m]];
}
return arr.slice(0, n);
};console.log(sampleSize([1, 2, 3], 2));
console.log(sampleSize([1, 2, 3], 4));➜code node sampleSize.js
[ 2, 1 ]
[ 1, 3, 2 ]
let m = arr.length;
while (m) {
const i = Math.floor(Math.random() * m--);
[arr[m], arr[i]] = [arr[i], arr[m]];
}

return arr.slice(0, n);

shuffle

Randomizes the order of the values of an array, returning a new array.

Uses the Fisher-Yates algorithm to reorder the elements of the array.

const shuffle = ([...arr]) => {
let m = arr.length;
while (m) {
const i = Math.floor(Math.random() * m--);
[arr[m], arr[i]] = [arr[i], arr[m]];
}
return arr;
};

➜code cat shuffle.js
const shuffle = ([...arr]) => {
let m = arr.length;
while (m) {
const i = Math.floor(Math.random() * m--);
[arr[m], arr[i]] = [arr[i], arr[m]];
}
return arr;
};const foo = [1, 2, 3];
console.log(shuffle(foo));
console.log(foo);➜code node shuffle.js
[ 1, 3, 2 ]
[ 1, 2, 3 ]

similarity

Returns an array of elements that appear in both arrays.

Use Array.filter() to remove values that are not part of values, determined using Array.includes().

const similarity = (arr, values) => arr.filter(v => values.includes(v));

➜code cat similarity.js
const similarity = (arr, values) => arr.filter(v => values.includes(v));console.log(similarity([1, 2, 3], [1, 2, 4]));
➜code node similarity.js
[ 1, 2 ]

filter的主体是第一个数组arr，最终将不满足条件的元素剔除掉。那么不满足的条件又是什么呢？

v => values.includes(v)

sortedIndex

Returns the lowest index at which value should be inserted into array in order to maintain its sort order.

Check if the array is sorted in descending order (loosely). Use Array.findIndex() to find the appropriate index where the element should be inserted.

const sortedIndex = (arr, n) => {
const isDescending = arr[0] > arr[arr.length - 1];
const index = arr.findIndex(el => (isDescending ? n >= el : n <= el));
return index === -1 ? arr.length : index;
};

➜code cat sortedIndex.js
const sortedIndex = (arr, n) => {
const isDescending = arr[0] > arr[arr.length - 1];
const index = arr.findIndex(el => (isDescending ? n >= el : n <= el));
return index === -1 ? arr.length : index;
};console.log(sortedIndex([5, 3, 2, 1], 4));
console.log(sortedIndex([30, 50], 40));➜code node sortedIndex.js
1
1

const index = arr.findIndex(el => (isDescending ? n >= el : n <= el));

isDescending ? n >= el : n <= el

return index === -1 ? arr.length : index;

sortedIndexBy

Returns the lowest index at which value should be inserted into array in order to maintain its sort order, based on a provided iterator function.

Check if the array is sorted in descending order (loosely). Use Array.findIndex() to find the appropriate index where the element should be inserted, based on the iterator function fn.

const sortedIndexBy = (arr, n, fn) => {
const isDescending = fn(arr[0]) > fn(arr[arr.length - 1]);
const val = fn(n);
const index = arr.findIndex(el => (isDescending ? val >= fn(el) : val <= fn(el)));
return index === -1 ? arr.length : index;
};

➜code cat sortedIndexBy.js
const sortedIndexBy = (arr, n, fn) => {
const isDescending = fn(arr[0]) > fn(arr[arr.length - 1]);
const val = fn(n);
const index = arr.findIndex(el => (isDescending ? val >= fn(el) : val <= fn(el)));
return index === -1 ? arr.length : index;
};console.log(sortedIndexBy([{ x: 3 }, { x: 4 }, { x: 5 }], { x: 4 }, o => o.x));➜code node sortedIndexBy.js
1

sortedIndexBy跟sortedIndex字面上只差一个By，一般而言By有基于xx的意思。

sortedLastIndex

Returns the highest index at which value should be inserted into array in order to maintain its sort order.

Check if the array is sorted in descending order (loosely). Use Array.map() to map each element to an array with its index and value. Use Array.reverse() and Array.findIndex() to find the appropriate last index where the element should be inserted.

const sortedLastIndex = (arr, n) => {
const isDescending = arr[0] > arr[arr.length - 1];
const index = arr
.map((val, i) => [i, val])
.reverse()
.findIndex(el => (isDescending ? n <= el[1] : n >= el[1]));
return index === -1 ? 0 : arr.length - index - 1;
};

➜code cat sortedLastIndex.js
const sortedLastIndex = (arr, n) => {
const isDescending = arr[0] > arr[arr.length - 1];
const index = arr
.map((v, i) => [i, v])
.reverse()
.findIndex(el => (isDescending ? n <= el[1] : n >= el[1]));return index === -1 ? 0 : arr.length - index;
};console.log(sortedLastIndex([10, 20, 30, 30, 40], 30));➜code node sortedLastIndex.js
4
const index = arr
.map((v, i) => [i, v])
.reverse()
.findIndex(el => (isDescending ? n <= el[1] : n >= el[1]));

// sortedLastIndex
isDescending ? n <= el[1] : n >= el[1]// sortedIndex
isDescending ? n >= el : n <= el

sortedLastIndex此时是对一个二维数组进行findIndex查找，二维数组的第二个元素即el[1]才是值，所以要跟它比较。sortedLastIndex的二维数组是经过翻转的，即如果本来数组是降序的，翻转后为升序，所以应该找元素n首次满足小于或等于数组元素el[1]的索引，而sortedIndex显然相反。

arr = [5, 4, 3, 3, 2, 1]

➜code cat sortedLastIndexSave.js
const sortedLastIndex = (arr, n) => {
const isDescending = arr[0] > arr[arr.length - 1];
const index = arr
.map(v => v)
.reverse()
.findIndex(el => (isDescending ? n <= el : n >= el));return index === -1 ? 0 : arr.length - index - 1;
};const arr = [10, 20, 30, 30, 40];
console.log(sortedLastIndex(arr, 30));
console.log(arr);➜code node sortedLastIndexSave.js
3
[ 10, 20, 30, 30, 40 ]

sortedLastIndexBy

Returns the highest index at which value should be inserted into array in order to maintain its sort order, based on a provided iterator function.

Check if the array is sorted in descending order (loosely). Use Array.reverse() and Array.findIndex() to find the appropriate last index where the element should be inserted, based on the iterator function fn..

const sortedLastIndexBy = (arr, n, fn) => {
const isDescending = fn(arr[0]) > fn(arr[arr.length - 1]);
const val = fn(n);
const index = arr
.map((val, i) => [i, fn(val)])
.reverse()
.findIndex(el => (isDescending ? val <= el[1] : val >= el[1]));
return index === -1 ? 0 : arr.length - index;
};

➜code cat sortedLastIndexBy.js
const sortedLastIndexBy = (arr, n, fn) => {
const isDescending = fn(arr[0]) > fn(arr[arr.length - 1]);
const val = fn(n);
const index = arr
.map((val, i) => [i, fn(val)])
.reverse()
.findIndex(el => (isDescending ? val <= el[1] : val >= el[1]));return index === -1 ? 0 : arr.length - index;
};console.log(sortedLastIndexBy([{ x: 4 }, { x: 5 }], { x: 4 }, o => o.x));
console.log(sortedLastIndexBy([{ x: 40 }, { x: 30 }, { x: 30 }, { x: 20 }, { x: 10 }], { x: 30 }, o => o.x));
console.log(sortedLastIndexBy([{ x: 10 }, { x: 20 }, { x: 30 }, { x: 30 }, { x: 40 }], { x: 30 }, o => o.x));➜code node sortedLastIndexBy.js
1
3
4

symmetricDifference

Returns the symmetric difference between two arrays.

Create a Set from each array, then use Array.filter() on each of them to only keep values not contained in the other.

const symmetricDifference = (a, b) => {
const sA = new Set(a),
sB = new Set(b);
return [...a.filter(x => !sB.has(x)), ...b.filter(x => !sA.has(x))];
};

➜code cat symmetricDifference.js
const symmetricDifference = (a, b) => {
const sA = new Set(a),
sB = new Set(b);
return [...a.filter(x => !sB.has(x)), ...b.filter(x => !sA.has(x))];
};console.log(symmetricDifference([1, 2, 3], [1, 2, 4]));➜code node symmetricDifference.js
[ 3, 4 ]

return [...a.filter(x => !sB.has(x)), ...b.filter(x => !sA.has(x))];

a.filter(x => !sB.has(x))这里保留a数组里所有不在b数组的集合里的元素，加上…展开运算符把这些元素拼接成数组，同理，对b数组也一样。

symmetricDifferenceBy

Returns the symmetric difference between two arrays, after applying the provided function to each array element of both.

Create a Set by applying fn to each array's elements, then use Array.filter() on each of them to only keep values not contained in the other.

const symmetricDifferenceBy = (a, b, fn) => {
const sA = new Set(a.map(v => fn(v))),
sB = new Set(b.map(v => fn(v)));
return [...a.filter(x => !sB.has(fn(x))), ...b.filter(x => !sA.has(fn(x)))];
};

➜code cat symmetricDifferenceBy.js
const symmetricDifferenceBy = (a, b, fn) => {
const sA = new Set(a.map(v => fn(v))),
sB = new Set(b.map(v => fn(v)));
return [...a.filter(x => !sB.has(fn(x))), ...b.filter(x => !sA.has(fn(x)))];
};console.log(symmetricDifferenceBy([2.1, 1.2], [2.3, 3.4], Math.floor));➜code node symmetricDifferenceBy.js
[ 1.2, 3.4 ]

symmetricDifferenceWith

Returns the symmetric difference between two arrays, using a provided function as a comparator.

Use Array.filter() and Array.findIndex() to find the appropriate values.

const symmetricDifferenceWith = (arr, val, comp) => [
...arr.filter(a => val.findIndex(b => comp(a, b)) === -1),
...val.filter(a => arr.findIndex(b => comp(a, b)) === -1)
];

➜code cat symmetricDifferenceWith.js
const symmetricDifferenceWith = (arr, val, comp) => [
...arr.filter(a => val.findIndex(b => comp(a, b)) === -1),
...val.filter(a => arr.findIndex(b => comp(a, b)) === -1),
];const res = symmetricDifferenceWith(
[1, 1.2, 1.5, 3, 0],
[1.9, 3, 0, 3.9],
(a, b) => Math.round(a) === Math.round(b)
);console.log(res);
➜code node symmetricDifferenceWith.js
[ 1, 1.2, 3.9 ]