创建数字数组的功能方法 [英] Functional way to create an array of numbers

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

问题描述

如何使用ES6在没有任何第三方库的情况下更功能地编写以下代码?

How could I write the following code more functionally using ES6, without any 3rd party libraries?

// sample pager array
// * output up to 11 pages
// * the current page in the middle, if page > 5
// * don't include pager < 1 or pager > lastPage
// * Expected output using example:
//     [9,10,11,12,13,14,15,16,17,18,19]

const page = 14 // by example
const lastPage = 40 // by example
const pagerPages = page => {
  let newArray = []
  for (let i = page - 5; i <= page + 5; i++) {
    i >= 1 && i <= lastPage ? newArray.push(i) : null
  }
  return newArray
}

我想避免使用Array.push,可能还有for循环,但我不确定在这种情况下如何实现它。

I would like to avoid Array.push, and possibly the for loop, but I'm not sure how I would achieve it in this situation.

推荐答案

功能编程不仅限于 reduce filter 地图;这是关于功能的。这意味着我们不必依赖于 Array.from({length:x})这样的反常知识,其中长度的对象属性可以像数组一样对待。对于初学者来说,这种行为是令人困惑的,而对于其他任何人来说都是精神上的开销。它认为你会喜欢编写更清晰地编码你的意图的程序。

Functional programming isn't limited to reduce, filter, and map; it's about functions. This means we don't have to rely on perverse knowledge like Array.from ({ length: x }) where an object with a length property can be treated like an array. This kind of behavior is bewildering for beginners and mental overhead for anyone else. It think you'll enjoy writing programs that encode your intentions more clearly.

reduce 以1或更多值开头并减少到(通常)单个值。在这种情况下,您实际上想要 c> c> reduce 的反向(或 fold ),这里称为展开。不同之处在于我们从单个值开始,并将展开扩展为(通常)多个值。

reduce starts with 1 or more values and reduces to (usually) a single value. In this case, you actually want the reverse of a reduce (or fold), here called unfold. The difference is we start with a single value, and expand or unfold it into (usually) multiple values.

我们从简化的示例开始,字母。我们开始展开初始值 97 ,字母 a 的字符代码。当char代码超过 122 时,我们停止展开,字母 z 的字符代码。

We start with a simplified example, alphabet. We begin unfolding with an initial value of 97, the char code for the letter a. We stop unfolding when the char code exceeds 122, the char code for the letter z.

const unfold = (f, initState) =>
  f ( (value, nextState) => [ value, ...unfold (f, nextState) ]
    , () => []
    , initState
    )

const alphabet = () =>
  unfold
    ( (next, done, char) =>
        char > 122
          ? done ()
          : next ( String.fromCharCode (char) // value to add to output
                 , char + 1                   // next state
                 )
    , 97 // initial state
    )
    
console.log (alphabet ())
// [ a, b, c, ..., x, y, z ]

上面,我们对状态使用单个整数,但其他展开可能需要更复杂的表示。下面,我们通过展开 [n,a,b] 的复合初始状态来显示经典斐波那契序列,其中 n 是递减计数器, a b 是用于计算序列条款的数字。这表明展开可用于任何种子状态,甚至数组或对象。

Above, we use a single integer for our state, but other unfolds may require a more complex representation. Below, we show the classic Fibonacci sequence by unfolding a compound initial state of [ n, a, b ] where n is a decrementing counter, and a and b are numbers used to compute the sequence's terms. This demonstrates unfold can be used with any seed state, even arrays or objects.

const fib = (n = 0) =>
  unfold
    ( (next, done, [ n, a, b ]) =>
        n < 0
          ? done ()
          : next ( a                   // value to add to output
                 , [ n - 1, b, a + b ] // next state
                 )
    , [ n, 0, 1 ] // initial state
    )

console.log (fib (20))
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765 ]

现在我们有写信分页的信心。同样,我们的初始状态是复合数据 [page,count] 因为我们需要跟踪要添加的页面 ,以及我们已经添加了多少页( count )。

Now we have the confidence to write pagination. Again, our initial state is compound data [ page, count ] as we need to keep track of the page to add, and how many pages (count) we've already added.

这种方法的另一个优点是你可以轻松地参数化 10 -5 +1 并且有一个合理的语义结构来放置它们。

Another advantage to this approach is that you can easily parameterize things like 10 or -5 or +1 and there's a sensible, semantic structure to place them in.

const unfold = (f, initState) =>
  f ( (value, nextState) => [ value, ...unfold (f, nextState) ]
    , () => []
    , initState
    )
    
const pagination = (totalPages, currentPage = 1) =>
  unfold
    ( (next, done, [ page, count ]) =>
        page > totalPages
          ? done ()
          : count > 10
            ? done ()
            : next (page, [ page + 1, count + 1 ])
    , [ Math.max (1, currentPage - 5), 0 ]
    )

console.log (pagination (40, 1))
// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]

console.log (pagination (40, 14))
// [ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ]

console.log (pagination (40, 38))
// [ 33, 34, 35, 36, 37, 38, 39, 40 ]

console.log (pagination (40, 40))
// [ 35, 36, 37, 38, 39, 40 ]

上面有两个条件会导致调用 done() 。我们可以使用 || 折叠它们,代码读得更好

Above, there are two conditions which result in a call to done (). We can collapse these using || and the code reads a little nicer

const pagination = (totalPages, currentPage = 1) =>
  unfold
    ( (next, done, [ page, count ]) =>
        page > totalPages || count > 10
          ? done ()
          : next (page, [ page + 1, count + 1 ])
    , [ Math.max (1, currentPage - 5), 0 ]
    )

这篇关于创建数字数组的功能方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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