【问题标题】:Filter in functional languages with original non-filtered elements?过滤具有原始未过滤元素的功能语言?
【发布时间】:2011-11-30 22:33:43
【问题描述】:

我想返回一个映射一些过滤元素的数组 - 但我想将非过滤元素保留在它们所在的位置。 即有没有简单的方法可以做到这一点?:

array
.filter(
  function(element){
    // some test
  }
)
.map(
  function(element){
    // some mapping
  }
)

我想出的最接近的解决方案是:

array
.map(
  function(value, index){
    if (<test>) {
      return <mapping>(value);
    }
  }
)

但我觉得这在某种程度上破坏了函数式编程的精神。

我不是要求特定的语言实现,尽管 Scala 或 JavaScript 中的示例会很好。

编辑:这是我正在寻找的具体示例:

[1,2,3,4,11,12]

将所有元素映射到 element*10,对于数组中大于 10 的所有元素,应该产生

[1,2,3,4,110,120]

EDIT2:我为使用“变异”这个词道歉。我并不是说要改变原始数组 - 我更多地考虑改变数组的副本。

【问题讨论】:

  • 第二个代码不会改变任何东西。除非您正在使用具有传递引用的未知 Javascript 版本进行编程。
  • 已修复,尽管代码最终看起来更糟。
  • 您能否提供您希望函数式语法看起来像的伪代码?
  • 类似于第一个代码 sn-p 的内容 - 我想将测试函数与变异函数分开。
  • 我显然遗漏了一些东西:您的第一个示例不正是您正在寻找的吗?

标签: javascript arrays list scala functional-programming


【解决方案1】:

您遇到的问题是您正在考虑过滤,而过滤不是您想要的。如果您不想删除元素,则它不是过滤器。

您只需要一张简单的地图:

array.map(x => if(x > 10) x * 10 else x)

或者,如果您认为您的条件过于复杂,

array.map {
    case x if x > 10 => x * 10
    case x => x
}

【讨论】:

    【解决方案2】:

    如果您使用的是可变集合,它实际上不会起作用。但是你可以在 Scala 中使用transform

    scala> val a = Array(1,2,3,4,11,12)
    a: Array[Int] = Array(1, 2, 3, 4, 11, 12)
    
    scala> a.transform {i => if(i > 10) i * 10 else i}
    res10: scala.collection.mutable.WrappedArray[Int] = WrappedArray(1, 2, 3, 4, 110, 120)
    

    编辑: 如果您想分离过滤器和地图,请使用view:

    scala> a
    res22: Array[Int] = Array(1, 2, 3, 4, 11, 12)
    
    scala> a.view.filter(_ > 10).transform(_ * 10)
    res23: scala.collection.mutable.IndexedSeqView[Int,Array[Int]] = SeqViewF(...)
    
    scala> a
    res24: Array[Int] = Array(1, 2, 3, 4, 110, 120)
    

    【讨论】:

    • 条件测试和实际映射太接近。例如,更改代码以使其仅映射并跳过条件会将其变成类似于a.transform {i =&gt; i * 10} 的内容。重新添加条件需要我在条件中“重新包装”映射(之前为if,之后为else)。
    【解决方案3】:

    这样的事情怎么样:(伪javascript)

      filteredMap = function(element) {
        if(filterFunc(element)){
          return mapFunc(element);
        }
        return element;
      }
    
    
      array = array.map(filteredMap)
    

    除非您明确要求对数组进行变异(这不是“功能性”),否则这应该可以得到您想要的。

    【讨论】:

      【解决方案4】:

      虽然原则上这些类型的操作是可能的,但 Scala 库不提供它们。

      您可以使用索引(或索引视图)构建自己的:

      scala> val a = Array(1,2,3,4,5)
      a: Array[Int] = Array(1, 2, 3, 4, 5)
      
      scala> a.indices.view.filter(i=>a(i)%2==0).foreach(i=>a(i)=0)
      
      scala> a
      res1: Array[Int] = Array(1, 0, 3, 0, 5)
      

      这有点尴尬,但通常比 if 语句版本好一点(至少你可以分别看到过滤器和分配步骤)。

      【讨论】:

        【解决方案5】:

        您可以将过滤器和映射功能提供给“组合”功能;我在http://jsfiddle.net/xtofl/UDbyL/ 上试过一个例子。

        这个想法是将“映射”(我称之为就地映射)应用于所有符合过滤谓词的元素在原始数组中

        【讨论】:

          【解决方案6】:

          collect 是你想要的吗?

          scala> List(2, 3, 5, 6, 9).filter(_ < 5).map(_ * 100)
          res30: List[Int] = List(200, 300)
          
          scala> List(2, 3, 5, 6, 9).collect { case i if i < 5 => i * 100 }
          res31: List[Int] = List(200, 300)
          

          【讨论】:

          • 我认为 OP 正在寻找稍微修改过的版本:List(2, 3, 5, 6, 9).collect { case i if someFilter(i) =&gt; someMap(i); case i =&gt; i}
          • @Jamil:这不是collect,这是map
          • @Debilski 然而,这正是他所要求的。
          • 贾米尔,丹尼尔:是的,我应该更仔细地阅读这个问题。
          【解决方案7】:

          何嘉伟利

          最简单的解决方案是将其重新分配给引用...即改变引用 而不是数据。如果参考在您的其他地方,这有一些好处 不会在他们眼皮底下变异。

          前:

          x = x.filter(filterOpp);
          

          ps!第二个例子有剂量工作。 总帐

          【讨论】:

          • 这不起作用,因为它只会返回过滤后的数组。我想要原始数组,其中过滤后的数组元素已发生变异。
          • 所以首先那不是功能性的,你信达错过了这一点。您不希望您的程序依赖于在它们下发生变异的引用。在它们之间放置一层间接层,就像一个带有获取当前版本数组的方法的对象。
          猜你喜欢
          • 1970-01-01
          • 2013-09-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-03-26
          • 2020-07-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多