我有一个java.lang.Iterable
懒惰地计算其值。我从Scala访问它。是否存在仅返回不同值的核心API方式?例如,成像有一个过滤方法,也提供了迄今为止返回的所有结果:
val myLazyDistinctIterable = iterable.filter((previousReturnedItems, newItem) => previousReturnedItems.contains(newItem))
我想这不是一般情况,因为它涉及存储以前返回的项目,这可能就是它不在核心API中的原因。
我知道List.distinct
和Set
但我想要的东西在被问到之前不会计算其元素。
答案 0 :(得分:11)
您可以在Stream
上使用distinct
方法。例如,如果您有Iterable
:
val it = new java.lang.Iterable[Int] {
def iterator = new java.util.Iterator[Int] {
var i = 0
var first = true
def hasNext = true
def next =
if (first) { first = false; i } else { first = true; i += 1; i - 1 }
def remove() { throw new UnsupportedOperationException("Can't remove.") }
}
}
你可以写:
scala> import scala.collection.JavaConverters._
import scala.collection.JavaConverters._
scala> val s = it.asScala.toStream
s: scala.collection.immutable.Stream[Int] = Stream(0, ?)
scala> s.take(10).toList
res0: List[Int] = List(0, 0, 1, 1, 2, 2, 3, 3, 4, 4)
scala> val s = it.asScala.toStream.distinct
s: scala.collection.immutable.Stream[Int] = Stream(0, ?)
scala> s.take(10).toList
res1: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
我们可以判断一切都是懒惰的,因为流是无限的。
答案 1 :(得分:6)
更新仔细阅读问题很好。在这个解决方案中没有懒惰。遗憾。
toSet
将完全符合您的要求:
实施例
val it = Seq(1,2,3,4,2,4): Iterable[Int]
it.toSet
// Set(1,2,3,4)
如果您觉得有点想象,可以将其转换回可迭代:
it.toSet.toIterable
或者,皮条客Iterable
:
implicit class UniquableIterable[T](t: Iterable[T]) {
def unique = t.toSet.toIterable
}
然后致电
it.unique
答案 2 :(得分:1)
扩展我上面的评论,但我现在无法测试:
def unique[A](it: Iterator[A]): Iterator[A] = {
val seen = mutable.Set[A]()
it.filter { a =>
if (seen(a))
false
else {
seen += a
true
}
}
}
至少你明白这个想法。然后,您可以将此应用于从迭代中获得的迭代器,而不会获得Stream
的不必要的存储行为。
答案 3 :(得分:1)
以下是将.disctinct
方法添加到Iterator
的代码。
implicit class IteratorWrapper[T](it: Iterator[T]) {
def distinct = new Iterator[T] {
var seen = Set.empty[T]
var ahead = Option.empty[T]
def searchAhead {
while (ahead.isEmpty && it.hasNext) {
val v = it.next
if (!seen(v)) {
seen += v
ahead = Some(v)
}
}
}
def hasNext = {
searchAhead
ahead.nonEmpty
}
def next = {
searchAhead
val result = ahead.get
ahead = None
result
}
}
}
请注意,对于迭代器通常如此,原始迭代器在调用.distinct
后无效。
答案 4 :(得分:-1)
这应该做的工作(但我讨厌):
class UniqueIterable[T](i: Iterable[T]) extends Iterable[T] {
import scala.collection.mutable.Set
def iterator = new Iterator[T] {
val it = i.iterator
var nextE: Option[T] = None
val seen: Set[T] = Set.empty
def hasNext = {
popNext()
nextE.isDefined
}
def next = {
popNext()
val res = nextE.get
nextE = None
res
}
@tailrec
private def popNext() {
if (nextE.isEmpty && it.hasNext) {
val n = it.next
if (seen contains n) popNext()
else {
seen += n
nextE = Some(n)
}
}
}
}
}