如何仅使用map
,reduce
或filter
或任何功能方式在阵列上创建自定义迭代?
假设我想将一个数组映射到另一个数组,该数组包含源数组中每三个相邻元素的总和:
var source = [1, 2, 3, 4, 6, 7, 8] // to [6, 17, 8]
或者制作两个元素:
var source = [1, 2, 3, 4, 5, 6, 7] // to [[1, 2], [3, 4], [5, 6], [7]]
对于第二个我有以下但是看起来不是很有用,因为我正在通过索引访问数组:
function* pairMap(data) {
yield* data.map((item, index) => {
if (index > 0) {
return [data[index - 1], item];
}
});
}
我对这样做的功能方式很感兴趣。
答案 0 :(得分:10)
假设我想将一个数组映射到另一个数组,该数组包含源数组中每三个相邻元素的总和:
var source = [1, 2, 3, 4, 6, 7, 8] // to [6, 17, 8]
地图创建1:1关系,因此这不适合map
。相反,reduce
或(“折叠”)在这里会更好。
const comp = f=> g=> x=> f (g (x));
const len = xs=> xs.length;
const isEmpty = xs=> len(xs) === 0;
const concat = xs=> ys=> ys.concat(xs);
const chunk= n=> xs=>
isEmpty (xs)
? []
: concat (chunk (n) (xs.slice(n))) ([xs.slice(0,n)]);
const reduce = f=> y=> xs=> xs.reduce((y,x)=> f(y)(x), y);
const map = f=> xs=> xs.map(x=> f(x));
const add = x=> y=> y + x;
const sum = reduce (add) (0);
var source = [1, 2, 3, 4, 6, 7, 8];
comp (map (sum)) (chunk (3)) (source);
//=> [ 6, 17, 8 ]
正如您所看到的,我们首先将source
转换为3的块,然后我们map
将sum
函数转换为每个块。
当你听到人们谈论“声明性”代码时,最后一行很清楚,并且对实现几乎不担心。我们没有告诉计算机 如何完成它的工作。没有for
/ while
循环,没有无关的变量或迭代器,没有逻辑等。
“idgaf如何,只需将source
分成3组,然后对每个部分求和”
// very declaration, wow
comp (map (sum)) (chunk (3)) (source);
或者制作两个元素:
var source = [1, 2, 3, 4, 5, 6, 7] // to [[1, 2], [3, 4], [5, 6], [7]]
使用上面相同的代码
var source = [1, 2, 3, 4, 5, 6, 7];
chunk (2) (source);
// => [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7 ] ]
对于第二个我有以下但是看起来不是很有用,因为我正在通过索引访问数组:
function* pairMap(data) { yield* data.map((item, index) => { if (index > 0) { return [data[index - 1], item]; } }); }
使用上面的代码,您可以轻松实现pairMap
const pairMap = f=> comp (map (f)) (chunk (2));
var source = [1, 2, 3, 4, 5, 6, 7];
pairMap (pair => console.log(pair)) (source);
// [ 1, 2 ]
// [ 3, 4 ]
// [ 5, 6 ]
// [ 7 ]
了解所有内容
问题是“自定义迭代的功能方式”。您会发现我的代码使用Array.prototype.reduce
和Array.prototype.map
排序作弊。学习如何自己构建这些是一个很好的学习工具,让我理解构建功能循环/迭代器/控件是有趣和简单的
const isEmpty = xs=> xs.length === 0
const head = xs=> xs[0];
const tail = xs=> xs.slice(1);
const reduce = f=> y=> xs=>
isEmpty (xs)
? y
: reduce (f) (f (y) (head (xs))) (tail (xs));
const add = x=> y=> y + x;
reduce (add) (0) ([1,2,3]);
//=> 6
有效!。
好的,让我们看看我们如何做地图
const concat = xs=> ys=> ys.concat(xs);
const append = x=> concat ([x]);
const map = f=>
reduce (ys=> x=> append (f (x)) (ys)) ([]);
const sq = x => x * x;
map (sq) ([1,2,3])
//=> [ 1, 4, 9 ]
测验1:您能否使用filter
撰写some
,every
和reduce
?
巨魔警告:实现这些功能的方法有很多种。如果你开始编写递归函数,你首先想要了解的是tail call是什么。 ES6正在进行尾部呼叫优化,但它暂时不会普及。有一段时间,Babel可以使用while循环来转换它,但它在版本6中暂时禁用,并且一旦修复它就会回来。
测验2 :如何通过适当的尾调用来重写reduce
?
答案 1 :(得分:2)
对于第一部分问题,您可以使用reduce
和slice
对数组中的每3个元素进行分组,然后您可以使用map
和reduce
来获取每个元素的总和基。
var source = [1, 2, 3, 4, 6, 7, 8];
var result = source.reduce((r, elem, i) => {
if(i % 3 == 0) r.push(source.slice(i, i+3));
return r;
}, []);
result = result.map(e => {return e.reduce((a, el) => { return a + el })});
console.log(result)
对于问题的第二部分,您可以再次使用reduce
和slice
对每两个元素进行分组。
var source = [1, 2, 3, 4, 5, 6, 7]
source = source.reduce((r, e, i) => {
if(i % 2 == 0) r.push(source.slice(i, i+2));
return r;
}, [])
console.log(source)
答案 2 :(得分:1)
第一项任务reduce
var source = [1, 2, 3, 4, 5, 6, 7];
var r1 = source.reduce((p, c, i, a) => {
if (i % 2) p[p.length - 1].push(c);
else p.push([a[i]]);
return p;
}, []);
console.log(JSON.stringify(r1, 0, 2));

reduce
和map
var source = [1, 2, 3, 4, 5, 6, 7];
var r2 = source.reduce((p, c, i, a) => {
if (p[p.length - 1].length < 3) p[p.length - 1].push(c);
else p.push([a[i]]);
return p;
}, [[]]).map(e => e.reduce((a, b) => a + b));
console.log(JSON.stringify(r2, 0, 2));
&#13;