我有以下迭代器:
val it = Iterator(("a",5),("a",3),("a",2),("a",1),("b",8),("b",2),("b",1),("c",1))
内部的值首先由第一个元素(String)排序,然后由第二个元素(Int)排序。如何从每个“字母”中获取前2个值。所以结果应该是那个例子:
Iterator(("a",5),("a",3),("b",8),("b",2),("c",1))
可以使用groupBy:
完成it.toList.groupBy(_._1).mapValues(_.take(2)).values.flatten.toIterator
但我希望看到一个解决方案,它遍历每个元素并检查前一个'string'元素,如果它相同且'count'小于2,那么它yield
这个值。
修改:
遵循@jwvh的逻辑答案:如何将前N个值代替前两个值进行推广?
答案 0 :(得分:3)
您可以使用fold
操作,但它比您的解决方案更麻烦:
val result = it.foldLeft((Seq[(String, Int)](), "", 0)){
case ((acc, prev, count), (l, n)) =>
if (prev == l) {
if (count < 2) (acc :+ (l, n), prev, count + 1)
else (acc, prev, count + 1)
}
else (acc :+ (l, n), l, 1)
}
println(result._1)
答案 1 :(得分:2)
使用foldLeft的另一个解决方案可能是:
it.foldLeft (List[(String, Int)]()) {
case (acc, (k,v)) if acc.takeWhile(_._1==k).size<2 => (k,v)::acc
case (acc, _) => acc
}.reverse
答案 2 :(得分:2)
如果我们不必同时使用整个迭代器,那可能会很好。
<强>已更新强>
case class LimitItr[A,B](var itr: Iterator[(A,B)], reps:Int) extends Iterator[(A,B)] {
private var memory: List[A] = List()
def hasNext = itr.hasNext
def next() = {
val current = itr.next
if (!memory.headOption.contains(current._1))
memory = List()
memory = current._1 :: memory
if (memory.length >= reps) {
itr = itr.dropWhile(_._1 == memory.head)
itr.hasNext // force the iterator forward
}
current
}
}
用法:
val repLimitedItr = LimitItr(itrOfTuples, numOfRepetitionsAllowed)