Javascript将方法链接到递归调用的结果

时间:2017-11-22 04:30:17

标签: javascript recursion slice

我试图从递归调用中返回一个字符串然后对其进行切片,但切片的行为很奇怪。

鉴于

let first = arr => arr.slice(0, 1)
let rest = arr => arr.slice(1)

let join = function join(arr, connector) { 
  return !arr.length ? '' : first(arr) + connector + join(rest(arr), connector)
}

let nums = [1, 2, 34, 45, 100]

其中join从数组值创建一个字符串,并使用连接符

join(nums, '-')

返回

"1-2-34-45-100-"

然后切掉最后一个' - '

"1-2-34-45-100-".slice(0, -1)

返回

"1-2-34-45-100"

function f() {
  return ("1-2-34-45-100-").slice(0, -1)
}
f()

返回     " 1-2-34-45-100"

足够简单。那么为什么在上面的递归调用的结果中添加一个切片,比如

let join = function join(arr, connector) { 
    return ( !arr.length ? '' : first(arr) + connector + join(rest(arr), connector) )
      .slice(0, -1); 
}

产生这个吗?

join(nums, '-')
// -> "1-2-34-45"
// shouldn't this be "1-2-34-45-100" ?

甚至是陌生人,

join([1,2,3,4,5,6,7,8,9,10], '-')
// -> "1-2-3-4-5-6"

切片是否涉及递归调用?

3 个答案:

答案 0 :(得分:1)

首先,您的first功能

存在问题
// first :: [a] -> [a] WUPS
let first = arr =>
  arr.slice(0, 1)

first应该返回第一个元素,不是包含第一个项目的单个元素数据

// first :: [a] -> a
const first = xs =>
  xs[0]

接下来,我们考虑一下函数的完整domain(输入)。您的函数接受一个字符串数组。该数组可以包含0,1或更多字符串,我们需要您的函数适用于所有情况 - codomain(输出)是字符串类型; join始终返回字符串

// contract
join ([])      == ''
join ([a])     == a
join ([a,b])   == a + '-' + b
join ([a,b,c]) == a + '-' + b + '-' + c

在JavaScript中将其编码为递归函数是微不足道的 - 请注意,不需要跟踪数组索引或担心增加迭代器 - 只需考虑履行合同



const first = xs =>
  xs[0]

const rest = xs =>
  xs.slice (1)

const join = xs => {
  switch (xs.length) {
    case 0:   return ''
    case 1:   return first (xs)
    default:  return first (xs) + '-' + join (rest (xs))
  }
}

console.log (join ([]))               // ''
console.log (join (['a']))            // 'a'
console.log (join (['a', 'b']))       // 'a-b'
console.log (join (['a', 'b', 'c']))  // 'a-b-c'




当然,如果我们允许用户指定加入字符串

,我们的功能可以大大改进



const first = xs =>
  xs[0]

const rest = xs =>
  xs.slice (1)

const join = (y, xs) => {
  switch (xs.length) {
    case 0:   return ''
    case 1:   return first (xs)
    default:  return first (xs) + y + join (y, rest (xs))
  }
}

console.log (join ('&', []))               // ''
console.log (join ('&', ['a']))            // 'a'
console.log (join ('&', ['a', 'b']))       // 'a&b'
console.log (join ('&', ['a', 'b', 'c']))  // 'a&b&c'




答案 1 :(得分:0)

每次运行slice时,将slice置于连接函数中都会导致join()

因为你在连接函数中进行递归,所以slice将被多次调用。

尝试在完成join()时调用切片。它会起作用。

let first = arr => arr.slice(0, 1)
let rest = arr => arr.slice(1)

let join = function join(arr, connector) { 
    return ( !arr.length ? '' : first(arr) + connector + join(rest(arr), connector) )
}

join([1,2,3,4,5,6,7,8,9,10], '-').slice(0, -1)

更新

根据您的顾虑,您可以这样编写代码:

const join = function(arr, connector) {
  const first = arr => arr.slice(0, 1)
  const rest = arr => arr.slice(1)

  const joinChain = function(arr, connector) {
    return ( !arr.length ? '' : first(arr) + connector + joinChain(rest(arr), connector) );
  }
  return joinChain(arr, connector).slice(0, -1);
}

join([1,2,3,4,5,6,7,8,9,10], '-')

答案 2 :(得分:0)

您应该只调整逻辑以避免尾随连接器。



extension myEnum {
    var description: String {
        let mirror = Mirror(reflecting: self)
        var result = ""
        for child in mirror.children {
            if let label = child.label {
                result += "\(label): \(child.value)"
            } else {
                result += "\(child.value)"
            }
        }
        return result
    }
}




A"休息参数"在嵌套函数上可以使这更简单。



let first = arr => arr.slice(0, 1)
let rest = arr => arr.slice(1)

let join = function join(arr, conn) { 
  return !arr.length ? "" :
          first(arr) + (arr.length === 1 ? "" : (conn + join(rest(arr), conn)))
}

let nums = [1, 2, 34, 45, 100]

console.log(join(nums, "-"));