2017-06-15 74 views
1

比方說,我有一個Scala元素集合和另一個與第一個集合相同大小的布爾集合(對於好奇的讀者,第二集合是Ramer-Douglas-Peucker algorithm的結果)。刪除集合中的所有索引

現在我想刪除第一個集合中的所有項目,其中第二個集合在同一個索引處具有false,一次傳遞,而不創建中間集合。我找不到任何可以實現它的Scala集合中的任何內置方法。當然,我可以寫我自己的,但我很驚訝斯卡拉集合已經不是一個。我只是想念它嗎?

例子:

List(1, 2, 3).removeWhere(List(false, true, false)) shouldEqual List(2) 
// removeWhere is an imaginary name for the method I'm looking for 

回答

1

我不知道這是否有資格作爲「一單通」,但你可以這樣做:

val list1 = List(1, 2, 3) 
val list2 = List(false, true, false) 
val filtered = list1.filter(elem => list2(list1.indexOf(elem))) 

然而,上面是不夠的,如果list1有重複元素。

另一種方式來做到這一點,這可能侵犯了您的「單通」的要求,就是:

val filtered = list1.zip(list2).filter(_._2).map(_._1) 
+1

這是二次,但仍然將工作做好的短名單,作爲一個例子。 「zip」解決方案是線性的(並且更短!)。 – 9000

+0

壓縮版本絕對更好 - 不要忘記'''list1.indexOf'''本身就是線性的。然後兩個通行證應該可以。 –

2

view工藝元素一個接一個。

scala> val xs = List(1,2,3).view.zip(List(true,false,true)).collect{case (x, true) => x} 
xs: scala.collection.SeqView[Int,Seq[_]] = SeqViewZFM(...) 

scala> xs.head 
res0: Int = 1 

scala> xs.tail 
res1: scala.collection.SeqView[Int,Seq[_]] = SeqViewZFMS(...) 
1

我很無聊,寫了手動版本:

def removeWhere_(l1 : List[Int], l2 : List[Boolean], acc : List[Int] => List[Int]) : List[Int] = { 
    (l1, l2) match { 
     case (x::xs, y::ys) if y => removeWhere_(xs,ys, f => acc(x :: f)) 
     case (x::xs, y::ys)  => removeWhere_(xs,ys, f => acc(f)) 
     case _ => acc(List()) 
    } 
    } 

def removeWhere(l1 : List[Int], l2 : List[Boolean]) = removeWhere_(l1, l2, x => x) 

不知道你從創建所有的仿函數允許尾調用優化的損失多少,但它只是一個穿越。

0

您可以將List轉換爲其對應的懶惰,一個Stream,然後用zipfilter

List(1, 2, 3).toStream.zip(List(false, true, false)).filter(_._2).map(_._1).toList 
相關問題