不知道这是否可行,但我有一些这样的代码:
val list = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
val evens = list.filter { e => e % 2 == 0 }
if(someCondition) {
val result = evens.filter { e => e % 3 == 0 }
} else {
val result = evens.filter { e => e % 5 == 0 }
}
但是我不想迭代所有元素两次,所以有没有办法可以在这个集合上创建一个“泛型选择全部数字”并应用其他一些函数,这样就可以了只迭代一次?
答案 0 :(得分:26)
如果您将list
变为惰性集合(例如Iterator
),则可以在一次传递中应用所有过滤操作(或其他内容,如map
等):< / p>
val list = (1 to 12).toList
val doubleFiltered: List[Int] =
list.iterator
.filter(_ % 2 == 0)
.filter(_ % 3 == 0)
.toList
println(doubleFiltered)
当您使用.iterator
将集合转换为迭代器时,Scala将跟踪要执行的操作(此处为两个filter
),但是等待执行它们,直到结果为止实际访问过(这里,通过调用.toList
)。
所以我可能会像这样重写你的代码:
val list = (1 to 12).toList
val evens = list.iterator.filter(_ % 2 == 0)
val result =
if(someCondition)
evens.filter(_ % 3 == 0)
else
evens.filter(_ % 5 == 0)
result foreach println
根据您要执行的操作,您可能需要Iterator
,Stream
或View
。它们都是懒惰计算的(因此一次通过方面将适用),但它们在诸如是否可以多次迭代(Stream
和View
)之类的事情上是不同的,或者它们是否保持计算值以后访问(Stream
)。
要真正看到这些不同的懒惰行为,请尝试运行此代码并将<OPERATION>
设置为toList
,iterator
,view
或toStream
:
val result =
(1 to 12).<OPERATION>
.filter { e => println("filter 1: " + e); e % 2 == 0 }
.filter { e => println("filter 2: " + e); e % 3 == 0 }
result foreach println
result foreach println
以下是您将看到的行为:
List
(或任何其他非惰性集合):每个filter
都需要在集合中单独迭代。生成的过滤集合存储在内存中,以便每个foreach
只能显示它。Iterator
:filter
和第一个foreach
都在一次迭代中完成。第二个foreach
没有做任何事情,因为已经消耗了Iterator
。结果不会存储在内存中。View
:两个foreach
调用都会在集合上进行自己的单遍迭代,以执行filters
。结果不会存储在内存中。Stream
:filter
和第一个foreach
都在一次迭代中完成。生成的过滤集合存储在内存中,以便每个foreach
只能显示它。答案 1 :(得分:8)
您可以使用功能组合。 someCondition
在决定使用哪个函数时只调用一次:
def modN(n: Int)(xs: List[Int]) = xs filter (_ % n == 0)
val f = modN(2) _ andThen (if (someCondition) modN(3) else modN(5))
val result = f(list)
(这不是你想要的 - 它仍然遍历列表两次)
这样做:
val f: Int => Boolean = if (someCondition) { _ % 3 == 0 } else { _ % 5 == 0 }
val result = list filter (x => x % 2 == 0 && f(x))
或者更好:
val n = if (someCondition) 3 else 5
val result = list filter (x => x % 2 == 0 && x % n == 0)
答案 2 :(得分:2)
这不会起作用:
list.filter{e => e % 2 == 0 && (if (someCondition) e % 3 == 0 else e % 5 == 0)}
同样FYI e % 2 == 0
将为您提供所有偶数,除非您出于其他原因命名val odds
。
答案 3 :(得分:1)
您只需在过滤器中写下两个条件:
val list = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
var result = List(0)
val someCondition = true
result = if (someCondition) list.filter { e => e % 2 == 0 && e % 3 == 0 }
else list.filter { e => e % 2 == 0 && e % 5 == 0 }