【问题标题】:Writing an inverse function in javascript?用javascript写一个反函数?
【发布时间】:2013-06-29 02:31:28
【问题描述】:

我今天在工作中遇到了一种情况,我需要编写我已经编写的函数的逆函数,但我发现手动编写逆函数效率低下,因为我似乎会重复很多我的代码,如果我要更新原始函数,我将不得不使用相应的更改来更新逆函数。我正在谈论的函数看起来像这样:

var f = function(id, str) {
  if (id === 0) {
    return str.substring(0, 4) + " " + str.substring(4, 8);
  } else if (id === 1) {
    return str.substring(0, 3) + "/" + str.substring(3, 8);
  } else if (id === 2) {
    return str.substring(0, 4) + "-" + str.substring(4, 8);
  } else if (id == 3) {
    return str.substring(0, 3) + "," + str.substring(3, 8);
  }
}

例如f(0, "ABCDEFGH") 将返回"ABCD EFGH"。我需要一个反函数,它使用函数f(id, str) 从输出中得出输入。所以finverse(formattedStr) 应该返回相应输入的字典。例如,finverse("ABCD EFGH") 应该返回 { id: 0, str: "ABCDEFGH" }。是否可以利用现有函数f 来编写这个逆函数,这样即使我用额外的“else if”子句更新原始函数,我也不必更新finverse。换句话说,我不想使用 if 语句手动构造 finverse 以将输出映射回输入,而是我想以某种方式操纵原始函数以提出逆向函数。这在javascript中可能吗?

【问题讨论】:

    标签: javascript function lambda functional-programming


    【解决方案1】:

    稍作重构,任务实际上非常简单。您不需要所有这些 if,实际上,if 的运行速度比 Object 属性查找慢,更不用说它们没有被密封在某个地方的私有函数中......

    我们可以在没有任何流逻辑的情况下完成翻译(1 进,1+ 出):

    // replace all the IF logic with an externally-modifiable logic table:
    f.lut=[ [4," "], [3,"/"], [4,"-"], [3,","]  ]; //(id=index, 0=pos, 1=char)
    
    
    // simplify f() using the table to make choices instead of conditionals:
    function f(id, str) {
       id = f.lut[id];
       return str.substring(0, id[0]) + id[1] + str.substring(id[0], 8);
    }
    
    
    // use the same table in reverse to compose an inverse function:
    function finverse(s){
        return  {
           id:   +f.lut.map(function(A,i){ return A[1]==s.split(/[\w]+/).filter(Boolean)[0] ? 
                             String(i):
                             ""
                 }).filter(Boolean)[0][0], 
           str:  s.split(/[\W]+/).filter(Boolean).join('')
        };
     }
    
    
    // first, test new version of f():
     f(0, "ABCDEFGH") // ABCD EFGH
     f(1, "ABCDEFGH") // ABC/DEFGH
     f(2, "ABCDEFGH") // ABCD-EFGH
     f(3, "ABCDEFGH") // ABC,DEFGH
    
    
    // now, test the inverse:
    finverse("ABCD EFGH")   //{id:0, str:"ABCDEFGH"}
    finverse("ABC/DEFGH")   //{id:1, str:"ABCDEFGH"}
    finverse("ABCD-EFGH")   //{id:2, str:"ABCDEFGH"}
    finverse("ABC,DEFGH")   //{id:3, str:"ABCDEFGH"}
    

    如果这不是您想要的,请告诉我们,我不是 100% 确定...

    【讨论】:

    • 我不知道.filter(Boolean) 的简写,不错。显然,这也适用于带有箭头功能的 ES6:.filter((x)=>!!x)。实际上也不需要将 arg 括在括号中:.filter(x=>!!x)
    • @cssimsek: .filter(x=>x) 将与 ES6 中的 .filter(Boolean) 实现相同 ;)
    • 这很好,所以不需要使用!!;在每次迭代中分配给x 的值都会隐式转换为其布尔值。
    • Array.prototype.boolFilter = function(){ return Array.prototype.filter.call(this,x=>x); }; 从崇高到荒谬。 :p
    【解决方案2】:

    真的没有办法让它完美地工作。这是不可能以良好的速度特性实现的。所以,我尝试给你两种方法来解决这个问题:

    1. 使用f()中使用的规则创建名为fRules的全局对象。

      fRules = [
        { 
           id: 0,
           char: ' ',
           insertPosition: 4
        },
      
        // ... other rules ...
      ];
      

      然后您可以在f() 中使用fRules,只需找到需要id 的规则,并在fInverse 中迭代规则数组并找到好的规则。现在不用改f(),只需要改fRules()

    2. f.toString() 获取函数文本并将函数解析为抽象语法树。就像 UglifyJs 的内部函数一样。阅读更多here。然后,您必须根据您的函数语法树手动编写一些逆变器。丑陋的想法

    【讨论】:

    • 您也可以使用计算机代数系统获得逆,因为某些 JavaScript 函数可以转换为数学表达式,反之亦然。
    猜你喜欢
    • 1970-01-01
    • 2021-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-14
    相关资源
    最近更新 更多