开发者

Filter in functional languages with original non-filtered elements?

I want to return an array that that maps some filtered elements - but I want to keep the non-filtered elements where they are. i.e. Is there an easy way to do this?:

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

The closest solution I've come up with is something along the lines of:

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

but I feel this somewhat breaks the spirit of functional programming.

I'm not asking for a specific language implementation, although an example in Scala or JavaScript would be nice.

EDIT: Here's a concrete example of what I'm looking for:

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

Mapping all elements to element*10, for all elements in array which are开发者_JS百科 greater than 10, should yield

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

EDIT2: I apologize for using the word "mutate." I did not mean mutate the original array - I was thinking more along the lines of mutating a copy of the array.


It's not really going to be functional if you're using a mutable collection. But you can use transform in Scala:

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)

edit: If you want filter and map separated, use a 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)


Is collect what you are after?

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)


You could provide your filter and map function to a 'combining' function; I've tried an example on http://jsfiddle.net/xtofl/UDbyL/.

The idea is to apply the 'mapping' (which I would call inplace mapping) to all elements conforming to the filtering predicate in the original array.


Although these sorts of operations are possible in principle, the Scala library does not provide them.

You can build your own using indices (or views on indices):

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)

It's slightly awkward, but usually a little better than the if-statement version (in that at least you can see the filter and assignment steps separately).


Hej jiaweihli

the easiest solution is to reassign it to the reference ... ie mutating the reference and not the data. This has some benefits if the reference is in other places you are not mutating it under there noses.

EX:

x = x.filter(filterOpp);

ps! the second example there dosent work. GL


The problem you are having is that you are thinking of filtering, and filtering is not what you want. If you don't want to remove elements, it is not a filter.

All you need is a simple map:

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

Or, if you think your conditions are too complex,

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


How about something like this: (psuedo javascript)

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


  array = array.map(filteredMap)

Unless you explicitly are required to mutate the array (which isn't "functional") this should get you what you want.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜