资讯专栏INFORMATION COLUMN

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

FrancisSoung / 1510人阅读

摘要:否则,直接循环去拼接该值返回按照指定的方法对数组元素进行分组归类。使用创建一个对象,对象的键是生成的结果,值是符合该键的所有数组元素组成的数组。微信公众号秒,从入门到放弃之三

原文链接:JavaScript30秒, 从入门到放弃之Array(三)

水平有限,欢迎批评指正

flattenDepth

Flattens an array up to the specified depth.

Use recursion, decrementing depth by 1 for each level of depth. Use Array.reduce() and Array.concat() to merge elements or arrays. Base case, for depth equal to 1 stops recursion. Omit the second element, depth to flatten only to a depth of 1 (single flatten).

const flattenDepth = (arr, depth = 1) =>
  depth != 1
    ? arr.reduce((a, v) => a.concat(Array.isArray(v) ? flattenDepth(v, depth - 1) : v), [])
    : arr.reduce((a, v) => a.concat(v), []);

把一个数组按指定深度进行摊平。

使用递归方法,对于任意级别的深度depth,每次递归depth1。使用Array.reduce()Array.concat()来合并元素们或者数组们。直到depth递减到1时停止递归。省略第二个参数depth时,按深度depth1计(即单层摊平)。

➜  code cat flattenDepth.js
const flattenDepth = (arr, depth = 1) =>
    depth != 1 ?
    arr.reduce((a, v) => a.concat(Array.isArray(v) ? flattenDepth(v, depth - 1) : v), []) :
    arr.reduce((a, v) => a.concat(v), []);

console.log(flattenDepth([1, [2], 3, 4]));
console.log(flattenDepth([1, [2, [5]], 3, 4]));
➜  code node flattenDepth.js
[ 1, 2, 3, 4 ]
[ 1, 2, [ 5 ], 3, 4 ]

根据depth来决定处理流程,depth存在且不等于1则进行递归:

arr.reduce((a, v) => a.concat(Array.isArray(v) ? flattenDepth(v, depth - 1) : v), [])

用了reduce()去处理循环时的每一个值,同时用concat把所有递归结果拼接成新数组返回。循环过程中,对值进行数组判断Array.isArray(v),是数组,flattenDepth(v, depth - 1)深度减1继续递归直到depth1为止;不是数组,直接返回该值v,供concat拼接。

否则,直接循环去拼接该值返回:

arr.reduce((a, v) => a.concat(v), []);
groupBy

Groups the elements of an array based on the given function.

Use Array.map() to map the values of an array to a function or property name. Use Array.reduce() to create an object, where the keys are produced from the mapped results.

const groupBy = (arr, func) =>
 arr.map(typeof func === "function" ? func : val => val[func]).reduce((acc, val, i) => {
   acc[val] = (acc[val] || []).concat(arr[i]);
   return acc;
 }, {});

按照指定的方法对数组元素进行分组归类。

使用Array.map()对所有数组元素调用指定方法或者调用返回该元素的属性值的方法。使用Array.reduce()创建一个对象,对象的键是map生成的结果,值是符合该键的所有数组元素组成的数组。

➜  code cat groupBy.js
const groupBy = (arr, func) =>
    arr.map(typeof func === "function" ? func : val => val[func]).
reduce((acc, val, i) => {
    acc[val] = (acc[val] || []).concat(arr[i]);
    return acc;
}, {});

console.log(groupBy([6.1, 4.2, 6.3], Math.floor));
console.log(groupBy(["one", "two", "three"], "length"));
➜  code node groupBy.js
{ "4": [ 4.2 ], "6": [ 6.1, 6.3 ] }
{ "3": [ "one", "two" ], "5": [ "three" ] }

代码拆分:

map

arr.map(typeof func === "function" ? func : val => val[func])

对第二个参数func的类型进行判断,若是function,则对数组arr所有元素调用该方法,返回一个新的数组。如:

const arr = [1, 2, 3, 4];
arr.map(x => x * x); // [1, 4, 9, 16]

否则,调用返回该元素对应func属性值方法:

const arr = ["one", "two", "three"];
const func = "length";
arr.map(val => val[func]); // [3, 3, 5]

reduce

reduce((acc, val, i) => {
  acc[val] = (acc[val] || []).concat(arr[i]);
  return acc;
}, {})

accreduce过程中累积的结果,valreduce的主体(即前边map的结果数组)每次循环时数组元素的值,i则是主体数组循环时对应的索引。

第一个循环时acc的初始值是一个空对象{},循环过程中先判断是否已经有以val为键的值,如果还没有,创建一个空数组把此时对应索引i的数组值arr[i]拼接,作为以val为键的值;否则,直接拼接arr[i]。即是acc[val] = (acc[val] || []).concat(arr[i])做的事。每次循环都返回acc对象,直到循环结束,生成分类结果。

连起来就是说先对数组arr元素进行mapmap结果作为键,所有map结果相同的数组元素arr[i]归到一个数组中作为该键的值。最终返回一个分好类的对象。

head

Returns the head of a list.

Use arr[0] to return the first element of the passed array.

const head = arr => arr[0];

返回数组第一个元素。

使用arr[0]返回指定数组arr的第一个元素。

➜  code cat head.js
const head = arr => arr[0];

console.log(head([1, 2, 3]));
➜  code node head.js
1
initial

Returns all the elements of an array except the last one.

Use arr.slice(0,-1) to return all but the last element of the array.

const initial = arr => arr.slice(0, -1);

返回除数组最后一个元素外的所有元素组成的新数组。

使用arr.slice(0, -1)返回数组除最后一个元素外的所有元素。

➜  code cat initial.js
const initial = arr => arr.slice(0, -1);

console.log(initial([1, 2, 3]));
➜  code node initial.js
[ 1, 2 ]

arr.slice(0, -1)立竿见影,实在没啥可说。

initialize2DArray

Initializes a 2D array of given width and height and value.

Use Array.map() to generate h rows where each is a new array of size w initialize with value. If the value is not provided, default to null.

const initialize2DArray = (w, h, val = null) =>
 Array(h)
   .fill()
   .map(() => Array(w).fill(val));

初始化一个给定宽(列)、高(行)和值的二维数组。

使用Array.map()来生成一个h行的数组。每一行含有w个值为指定值的元素。如果未指定任何值,数组的默认值是null

➜  code cat initialize2DArray.js
const initialize2DArray = (w, h, val = null) => Array(h).fill().map(() => Array(w).fill(val));

console.log(initialize2DArray(2, 2, 0));
➜  code node initialize2DArray.js
[ [ 0, 0 ], [ 0, 0 ] ]

Array(h).fill()先创建一个含有h个元素的数组并将它们全部默认填充为undefined。然后在生成的数组基础上,每个数组元素调用一个生成w个元素的数组且每个位置的值都填充为val方法。这样就生成了hw列的二维数组。

initializeArrayWithRange

Initializes an array containing the numbers in the specified range where start and end are inclusive.

Use Array((end + 1) - start) to create an array of the desired length, Array.map() to fill with the desired values in a range. You can omit start to use a default value of 0.

const initializeArrayWithRange = (end, start = 0) =>
 Array.from({ length: end + 1 - start }).map((v, i) => i + start);

初始化一个包含startend的有序数值的数组。

使用Array((end + 1) - start)生成所期望的数组,使用Array.map()去填充所期望的有序的数值。若省略start,则start默认值为0

➜  code cat initializeArrayWithRange.js
const initializeArrayWithRange = (end, start = 0) =>
    Array.from({
        length: end + 1 - start
    }).map((v, i) => i + start);

console.log(initializeArrayWithRange(5));
console.log(initializeArrayWithRange(7, 3));
➜  code node initializeArrayWithRange.js
[ 0, 1, 2, 3, 4, 5 ]
[ 3, 4, 5, 6, 7 ]

{length: end + 1 - start}生成的数组长度是end + 1 -start,而(v, i) => i + starti0开始循环,直到length - 1为止。而i + start则表示元素值从0 + start开始递增。

initializeArrayWithValues

Initializes and fills an array with the specified values.

Use Array(n) to create an array of the desired length, fill(v) to fill it with the desired values. You can omit value to use a default value of 0.

const initializeArrayWithValues = (n, value = 0) => Array(n).fill(value);

初始化一个数组并全部填充指定值。

Array(n)生成期望长度的数组,fill(v)填充期望的值。若省略第二个参数value,则value默认为0

➜  code cat initializeArrayWithValues.js
const initializeArrayWithValues = (n, value = 0) => Array(n).fill(value);

console.log(initializeArrayWithValues(5, 2));
➜  code node initializeArrayWithValues.js
[ 2, 2, 2, 2, 2 ]

Array(n).fill(value)一步到位,没啥可说的了。

intersection

Returns a list of elements that exist in both arrays.

Create a Set from b, then use Array.filter() on a to only keep values contained in b.

const intersection = (a, b) => {
  const s = new Set(b);
  return a.filter(x => s.has(x));
};

返回两个数组的交集。

首先创建一个b数组的集合,然后使用Array.filter()去筛选出a数组中存在于b数组中的元素。

➜  code cat intersection.js
const intersection = (a, b) => {
    const s = new Set(b);
    return a.filter(x => s.has(x));
};

console.log(intersection([1, 2, 3], [4, 3, 2]));
➜  code node intersection.js
[ 2, 3 ]

const s = new Set(b)先用集合把b数组去重,然后a.filter(x => s.has(x))过滤数组a,返回所有存在于s集合中元素组成的数组。

last

Returns the last element in an array.

Use arr.length - 1 to compute the index of the last element of the given array and returning it.

const last = arr => arr[arr.length - 1];

返回数组的最后一个元素。

arr.length - 1去计算一个数组最后一个元素的索引值并返回其对应的数组元素。

➜  code cat last.js
const last = arr => arr[arr.length - 1];

console.log(last([1, 2, 3]));
➜  code node last.js
3
mapObject

Maps the values of an array to an object using a function, where the key-value pairs consist of the original value as the key and the mapped value.

Use an anonymous inner function scope to declare an undefined memory space, using closures to store a return value. Use a new Array to store the array with a map of the function over its data set and a comma operator to return a second step, without needing to move from one context to another (due to closures and order of operations).

const mapObject = (arr, fn) =>
  (a => (
    (a = [arr, arr.map(fn)]), a[0].reduce((acc, val, ind) => ((acc[val] = a[1][ind]), acc), {})
  ))();

把一个数组调用指定的方法后生成一个对象,对象的键是数组的元素值,对象的值是该元素值调用指定方法后生成的结果

使用内部匿名函数定义一个不污染全局变量的命名空间并用闭包存储返回值。使用一个新的数组来存储一个包含arr数组和arr数组去map指定方法后生成的数组。并在前面数组的基础上借助,运算符去一步步的生成所需要的对象。避免了上下文环境context来回转换(得益于闭包和运算顺序)。 (这块不是太懂)

➜  code cat mapObject.js
const mapObject = (arr, fn) =>
    (a => (
        (a = [arr, arr.map(fn)]), a[0].reduce((acc, val, ind) => ((acc[val] = a[1][ind]), acc), {})
    ))();

const squareIt = arr => mapObject(arr, a => a * a);
console.log(squareIt([1, 2, 3]));
➜  code node mapObject.js
{ "1": 1, "2": 4, "3": 9 }

逗号运算符会返回最后一个运算表达式运算的结果,如:

const i = 0
i + 1, i // i = 1

即先进行i + 1运算,为1,然后返回i1

以上代码含有两个逗号运算表达式:

((acc[val] = a[1][ind]), acc)

即先做(acc[val] = a[1][ind])这个运算,然后返回acc

第二个是:

(a = [arr, arr.map(fn)]), a[0].reduce((acc, val, ind) => ((acc[val] = a[1][ind]), acc), {})

即在a = [arr, arr.map(fn)]定义了a的基础上去运用后面的reduce方法,最后返回reduce方法的结果。

可以看出,先定义了一个长度为2的数组a,索引0对应值为数组arr,索引1对应值为数组arr调用fn后的map结果数组。然后去reduce生成以arr元素值为对象键(即val,也即a[0]数组遍历过程中的元素值),以对应该元素值调用fn后的结果值(即a[1][ind])为对象值的对象。这个对象就是最终想要的结果。

一个时间处理库:now.js,觉得还行的话,点个赞再走呗。。。

微信公众号:JavaScript30秒, 从入门到放弃之Array(三)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90558.html

相关文章

  • JavaScript30入门放弃Array(二)

    摘要:循环一个数组,使用每次去删除该数组的第一个元素直到指定方法运算结果为,返回的是剩余元素组成的数组。直到循环退出,返回此时的。对应就是,包含下界,不包含上届。秒,从入门到放弃之二微信公众号秒,从入门到放弃之二 difference Returns the difference between two arrays. Create a Set from b, then use Array...

    pinecone 评论0 收藏0
  • JavaScript30入门放弃Array(五)

    摘要:原文地址秒,从入门到放弃之五博客地址秒,从入门到放弃之五水平有限,欢迎批评指正从给定的数组中随机选出指定个数的数组元素。否则判断数组元素是否大于或者等于指定元素,寻找过程与前边类似。 原文地址:JavaScript30秒, 从入门到放弃之Array(五)博客地址:JavaScript30秒, 从入门到放弃之Array(五) 水平有限,欢迎批评指正 sampleSize Gets n...

    dunizb 评论0 收藏0
  • JavaScript30入门放弃Array(六)

    摘要:从数组索引为开始删除元素,直到对数组元素运用指定方法为为止。对两个数组的元素分别调用指定方法后,返回以运行结果为判定基准的并集,并集是原始数组元素的并集而不是运行结果的并集。 原文地址:JavaScript30秒, 从入门到放弃之Array(六)博客地址:JavaScript30秒, 从入门到放弃之Array(六) 水平有限,欢迎批评指正 tail Returns all elem...

    Freeman 评论0 收藏0
  • JavaScript30入门放弃Array(七)

    摘要:地址秒,从入门到放弃之七博客地址秒,从入门到放弃之七水平有限,欢迎批评指正剔除掉数组中所有存在于所指定的元素们的项。使用,和来创建由两个数组元素拼接而成的所有可能对并将它们存在一个数组中的数组。 GitHub地址:JavaScript30秒, 从入门到放弃之Array(七)博客地址:JavaScript30秒, 从入门到放弃之Array(七) 水平有限,欢迎批评指正 without ...

    Cciradih 评论0 收藏0
  • JavaScript30入门放弃

    摘要:三元运算符遍历过程中判断遍历数组值是否严格等于指定值,是,次数否,。三元运算符判断是否是一个数组,是,返回递归运用后的值否,直接返回。秒,从入门到放弃博客地址秒,从入门到放弃微信公众号地址秒,从入门到放弃 有意思 最近很火的github上的库30-seconds-of-code,特别有意思,代码也很优雅。 能学es6 自己翻译,能学英语 代码很美,很优雅,美即正义 函数式表达,享受 ...

    TNFE 评论0 收藏0

发表评论

0条评论

FrancisSoung

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<