自定义迭代的功能方式 [英] Functional way for custom iteration

查看:113
本文介绍了自定义迭代的功能方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何只使用 map reduce 过滤器或任何函数的方式来创建一个数组的自定义迭代?



假设我想映射一个数组到另一个数组中,每个数组包含三个相邻元素的总和源数组:

  var source = [1,2,3,4,6,7,8] // to [ 6,17,8] 

或者制作两个元素桶:

  var source = [1,2,3,4,5,6,7] //到[[1,2],[3,4] ,[5,6],[7]] 

对于第二个,我有以下但看起来没有什么功能,因为我按索引访问数组:

  function * pairMap(data){
如果(索引> 0){
return [data [index-1],item];
} $ b,则返回* data.map((item,index)=> $ b});
}

我对这样做的功能感兴趣。

解决方案


假设我想将一个数组映射到另一个数组,源数组中的元素:

  var source = [1,2,3,4,6,7,8] //至[6,17,8] 


地图创建1:1关系,所以这不适合使用 map 。相反, reduce 或(fold)在这里会更好。

  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 => ((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 函数。

当您听到有人在谈论声明式代码时,最后一行非常清晰,并且对实现操作很少担心。我们并没有告诉计算机如何做它的工作。没有用于 / ,而循环,没有额外的变量或迭代器,没有逻辑等。
$ b

idgaf怎么样,只要把 source 分成3个组,然后求和每个部分

  //非常声明,哇
comp(map(sum))(chunk(3) )) (资源);







桶中的两个元素:

  var source = [1,2,3,4,5,6,7] //到[b] [b] 


$ [[1,2],[3,4],[5,6],[7] b
$ b

使用上面相同的代码

  var source = [1,2,3,4 ,5,6,7]; 
chunk(2)(source);
// => [b] [b] [b] [b] [b] [b] [b] [b] [b] [b] [b] [b] [b] hr>


对于第二个,我有以下内容,但由于我按索引访问数组,因此看起来不太有用:

 函数* pairMap(data){
yield * data.map((item,index)=> {
if (index> 0){
return [data [index - 1],item];
}
});

$ / code>


使用上面的代码,您可以实现 pairMap easy

  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(f)(f(y)(head(xs)))(tail(xs));

const add = x => Y => y + x;
reduce(add)(0)([1,2,3]);
// => 6

确实有效!



确定,让我们看看我们该怎么做map

  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: code> filter 一些每个使用减少



巨魔警告:实现这些功能的方法有很多。如果您开始编写递归函数,您首先需要了解的是 tail call

是。 ES6正在实现尾部呼叫优化,但一段时间后它不会普及。有一段时间,Babel可以使用while循环来传递它,但它在版本6中暂时被禁用,并且一旦修复就会回来。



测验2:如何用适当的尾声重写我的 reduce

How can I use only map, reduce or filter or any functional way to create a custom iteration on an array?

Let's say I wanna map an array to another array which holds the sum of each three adjacent elements in the source array:

var source = [1, 2, 3, 4, 6, 7, 8] // to [6, 17, 8]

Or make a bucket of two elements:

var source = [1, 2, 3, 4, 5, 6, 7] // to [[1, 2], [3, 4], [5, 6], [7]]

For the second one I have the following but that doesn't look very functional as I'm accessing array by index:

function* pairMap(data) {
    yield* data.map((item, index) => {
        if (index > 0) {
            return [data[index - 1], item];
        }
    });
}

I'm interested in the functional way of doing this.

解决方案

Let's say I wanna map an array to another array which holds the sum of each three adjacent elements in the source array:

var source = [1, 2, 3, 4, 6, 7, 8] // to [6, 17, 8]

Maps create 1:1 relationships, so this wouldn't be appropriate use of map. Instead, a reduce or ("fold") would be better here.

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 ]

So as you can see, we first transform the source into chunks of 3, then we map the sum function over each chunk.

When you hear people talking about "declarative" code, the last line is quite clear and worries little about implementation. We're not telling the computer how to do its job. There's no for/while loops, no extraneous vars or iterators, no logic, etc.

"idgaf how, just break source up into groups of 3, and then sum each part"

// very declaration, wow
comp (map (sum)) (chunk (3)) (source);


Or make a bucket of two elements:

var source = [1, 2, 3, 4, 5, 6, 7] // to [[1, 2], [3, 4], [5, 6], [7]]

Using the same code above

var source = [1, 2, 3, 4, 5, 6, 7];
chunk (2) (source);
// => [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7 ] ]


For the second one I have the following but that doesn't look very functional as I'm accessing array by index:

function* pairMap(data) {
      yield* data.map((item, index) => {
         if (index > 0) {
              return [data[index - 1], item];
          }
      });
  }

Using the code above, you can implement pairMap easily

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 ]


Learn all the things

The question is "functional way for custom iteration". You'll notice my code sorta cheats by using Array.prototype.reduce and Array.prototype.map. Learning how to build these on your own was a good learning tool for me to understand that building functional loops/iterators/control is fun and simple

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

It works!.

OK, let's see how we'd do map

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 ]

Quiz 1: Can you write filter, some, and every using reduce ?

Troll warning: There's many different ways to implement these functions. If you start writing recursive functions, the first thing you'll want to learn about is what a tail call is. ES6 is getting tail call optimization but it won't be widespread for a while. For a while, Babel could transpile it using a while loop, but it's temporarily disabled in version 6 and will be coming back once they fix it.

Quiz 2: How can you rewrite my reduce with a proper tail call?

这篇关于自定义迭代的功能方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆