JavaScript30秒, 从入门到放弃之Array(五)

原文地点:
JavaScript30秒, 从入门到放弃之Array(五)

博客地点:JavaScript30秒, 从入门到放弃之Array(五)

程度有限,迎接批评指正

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);
};

从给定的数组中随机选出指定个数的数组元素。

Fisher-Yates 算法将数组洗牌(打乱递次)。然后应用Array.slice() 来截取数组的前n个元素。假如省略第二个参数n,按n=1处置惩罚,即仅取一个随机元素。

➜  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]];
}

症结点是这个while轮回,按数组初始长度m每次递减1轮回,然后连系Math.floorMath.randomm范围内天生一个随机索引。用该索引对应的数组元素与索引m-1(即未交流过的末了一个元素)对应数组元素交流位置。轮回完毕,数组洗牌胜利。

return arr.slice(0, n);

末了返回被截取的前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;
};

对指定数组举行随机排序并返回排好序的新数组。

Fisher-Yates 算法将数组洗牌(打乱递次)并返回排好序的新数组。

➜  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 ]

这就是前面sampleSize用到的算法,注重的是返回的是新的数组,不是在原数组上举行排序的。

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));

返回一个包括两个数组的配合元素的数组。

应用Array.filter()连系Array.includes()把一个数组中不属于第二个数组values的元素都剔除。

➜  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)

条件是第一个数组arr不在第二个数组values里的一切元素,也即仅保存满足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;
};

返回一个元素应当插进去到已知排好序的数组而且不转变该数组排序体式格局的最小索引。

搜检一个数组是不是已按降序分列(松懈的),然后应用Array.findIndex()去找出指定的元素应当插在数组中适宜位置的索引并返回。

➜  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

之所以叫sortedIndex是由于数组已排序了,但升序降序未知。为此只需比较数组第一个元素arr[0]和数组末了一个元素arr[arr.length - 1]的大小即可推断升降序。

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

这里有一个三元运算表达式:

isDescending ? n >= el : n <= el

假如是降序的,推断数组arr元素el是不是小于或许等于指定元素n,也就是说,当满足指定数组元素n初次大于或许等于arr遍历历程当中恣意一个元素el的时刻,就返回此时的索引。不然推断数组arr元素el是不是大于或许等于指定元素n,寻觅历程与前边相似。

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

末了,推断所找索引index是不是为-1,如果,申明narr一切元素要小,应当放在arr末了一名,即index = 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;
};

返回一个元素应当插进去到已知排好序的数组而且不转变该数组排序体式格局的最小索引,条件是受一个指定的要领安排。

搜检一个数组是不是已按降序分列(松懈的),然后应用Array.findIndex()去找出指定的元素应当插在数组中适宜位置的索引并返回,条件是受一个指定的要领安排。

➜  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

sortedIndexBysortedIndex字面上只差一个By,一般而言By基于xx的意义。

这里就是基于某个要领fn,意即在findIndex找适宜元素的时刻指的是对元素挪用fn后的效果来举行比较,而不是元素自身。别的要注重的是,推断原数组arr升降序是也是fn挪用效果的升降序,而不是元素自身的升降序。

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;
};

返回一个元素应当插进去到已知排好序的数组而且不转变该数组排序体式格局的最大索引(从右侧数的最小索引)。

搜检一个数组是不是已按降序分列(松懈的),然后应用Array.map()把原数组map一个包括索引和元素值的二维数组,在此map后的数组上用Array.findIndex()去找出指定的元素应当插在数组从右侧数的适宜位置的索引并返回。

➜  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]));

首先用原数组arrmap一个二维数组,至于为何肯定要去map待会再讲。

然后reverse()去把map后的二维数组翻转。

末了在翻转数组基本上去查找对应索引:

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

// sortedIndex
isDescending ? n >= el : n <= el

这里不难看出sortedLastIndexsortedIndex的三元运算表达式是不一样的。

  • sortedLastIndex此时是对一个二维数组举行findIndex查找,二维数组的第二个元素即el[1]才是值,所以要跟它比较。
  • sortedLastIndex的二维数组是经由翻转的,即假如原本数组是降序的,翻转后为升序,所以应当找元素n初次满足小于或等于数组元素el[1]的索引,而sortedIndex明显相反。

终究再对找出来的是索引index举行推断,假如index === -1,那末应当返回0,怎样讲?

关于-1来讲,从右侧数起,把全部数组数完了,都没有找到能放它的位置,那末只要数组第一个位置相符它。

假如index !== -1,也就是找到一个适宜的索引,然则这个index是从右侧数的,转换成从左侧数的索引就是arr.length - index,(原文是arr.length – index – 1)我认为是错的。举个例子:

arr = [5, 4, 3, 3, 2, 1]
要把3插进去数组arr的从右侧数是2;
从左侧数是4,等于:6 - 2 = 4

接着前面说的为何肯定须要mapmap是返回一个新的数组而不转变原数组,arr.reverse()是会直接转变原数组arr的,arr.map(fn).reverse()则不会转变arr而只是转变了arr.map(fn)后返回的数组。

但是我个人以为map的时刻没必要返回一个二维数组,直接一维数组就能够了,由于后续基础用不到map后的第一个元素el[0]即它对应的索引。

如:

➜  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 ]

效果一样,而且原数组arr并未转变。

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;
};

返回一个元素应当插进去到已知排好序的数组而且不转变该数组排序体式格局的最大索引(从右侧数的最小索引),条件是受一个指定的要领安排。

搜检一个数组是不是已按降序分列(松懈的),然后应用Array.reverse()Array.findIndex()去找出指定的元素应当插在数组从右侧数的适宜位置的索引并返回,条件是受一个指定的要领安排。

➜  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

这个跟前面的sortedLastIndex差异实在就是是不是挪用fn后再比较的题目,没啥可说的了。

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))];
};

返回两个数组中对称不相同的元素(简单说就是数组a中不存在于数组b中的一切元素加上数组b中不存在于数组a中的一切元素)。

对两个数组离别建立其鸠合。然后离别应用Array.filter()过滤出不存在于对方的一切元素。

➜  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那行:

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)))];
};

返回两个数组中对称不相同的元素,条件是对两个数组一切元素挪用指定要领后。(简单说就是数组a中不存在于数组b中的一切元素加上数组b中不存在于数组a中的一切元素,条件是挪用指定要领后)。

对两个数组离别挪用指定要领后建立其鸠合。然后离别应用Array.filter()过滤出不存在于对方的

➜  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 ]

symmetricDifference的差别点在于多了一个fn,所以在建立鸠合之前,要先对数组元素map一个对一切元素应用fn的要领。再各自过滤的时刻也一样应用fn对数组元素举行挪用。

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)
];

返回两个数组中对称不相同的元素,条件是应用一个指定的比较要领举行比较。

应用Array.filter()Array.findIndex()来找出相符条件的一切元素。

➜  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 ]

这个就是对数组arr,过滤出对数组arrval一切元素挪用comp要领后效果差别的一切元素。同理对数组val也一样。然后二者的效果拼接成终究的效果。

    原文作者:supermao
    原文地址: https://segmentfault.com/a/1190000013245645
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞