【问题标题】:How can I rewrite this function with tail recursion如何用尾递归重写这个函数
【发布时间】:2016-01-14 14:54:03
【问题描述】:

我编写了以下函数来线性化任意 HTML 字符串的文本内容:

html2text(html) {
    function _html2text(element, accum) {
        return Array.prototype.slice.call(element.childNodes).reduce((accum, node) => {
            return (node.nodeType === 3)
                ? `${accum} ${node.textContent}`
                : _html2text(node, accum);
        }, accum);
    }
    const div = document.createElement('div');
    div.innerHTML = html;
    return _html2text(div, '');
}

但现在我无法将其转换为跟踪递归样式以便对其进行优化。 我的问题是递归在减少中重复出现。 我将把它写成循环,但我无法对它进行尾部递归,这让我很生气。


这是我的循环版本:

function html2text(html) {
    var div = document.createElement('div');
    div.innerHTML = html;
    var accum = '';
    var stack = [];
    stack.push([div, 0]);
    while (stack.length !== 0) {
        var frame = stack.pop();
        var el = frame[0];
        var i = frame[1];
        for (; i < el.childNodes.length; i++) {
            var node = el.childNodes[i];
            if (node.nodeType === Node.ELEMENT_NODE) {
                stack.push([el, i+1]);
                stack.push([node, 0]);
                break;
            } else if (node.nodeType === Node.TEXT_NODE) {
                accum += ' ' + node.textContent;
            }
        }
    }
    return accum;
}

这是上面用递归尾调用编写的函数,传递堆栈:

function html2text(html) {                                                                                                                                                                              

    function recurse(stack, accum) {                                                                                                                                                                    
        if (!stack.length) {                                                                                                                                                                            
            return accum;                                                                                                                                                                               
        }                                                                                                                                                                                               
        var frame = stack.pop();                                                                                                                                                                        
        var el = frame[0];                                                                                                                                                                              
        var i = frame[1];                                                                                                                                                                               
        for (; i < el.childNodes.length; i++) {                                                                                                                                                         
            var node = el.childNodes[i];                                                                                                                                                                
            if (node.nodeType === Node.ELEMENT_NODE) {                                                                                                                                                  
                stack.push([el, i+1]);                                                                                                                                                                  
                stack.push([node, 0]);                                                                                                                                                                  
                break;                                                                                                                                                                                  
            } else if (node.nodeType === Node.TEXT_NODE) {                                                                                                                                              
                accum += ' ' + node.textContent;                                                                                                                                                        
            }                                                                                                                                                                                           
        }                                                                                                                                                                                               
        return recurse(stack, accum)                                                                                                                                                                    
    }                                                                                                                                                                                                   

    var div = document.createElement('div');                                                                                                                                                            
    div.innerHTML = html;                                                                                                                                                                               
    var stack = [];                                                                                                                                                                                     
    stack.push([div, 0]);                                                                                                                                                                               
    return recurse(stack, '');                                                                                                                                                                          
} 

内部循环可以转换为另一个递归,但如果不使用不可变数据结构,这对我来说没有太大意义。

【问题讨论】:

  • 有es6标签吗?由于胖箭头和尾递归是新功能,因此看起来很合适。
  • 据我所知,ES6 中没有跟踪递归优化;这就是我蹦床的原因。粗箭头只是语法。
  • reduction 来自哪里?
  • @plalx Array#reduce()
  • 搜索尾递归树遍历。

标签: javascript recursion functional-programming computer-science tail-recursion


【解决方案1】:
function html2text(current, text = "") {
    "use strict";
    if (current === null) return text;
    var nextNode = current.nextSibling || current.parentNode.nextSibling,
        more = current.nodeType === 3 ? current.textContent : "";
    return html2text(nextNode, text + more);
}

你是对的,你可以在尾调用之前进行连接。我认为这符合所有标准,但 ES6 是新的,所以请仔细检查。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多