在Scala中迭代:检查以前的值

时间:2016-07-28 09:02:27

标签: scala iterator

我有以下迭代器:

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个值代替前两个值进行推广?

3 个答案:

答案 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)