迭代列表,返回当前,下一个和当前之前的元素

时间:2010-01-25 19:50:06

标签: scala list iteration tuples

我在以scala-esque和优雅的方式编写特定应用程序时遇到问题。我现在尝试了一段时间,但是找不到这个问题的“好”解决方案:

鉴于我有以下列表:

List("foo", "bar", "baz", "blah")

我想迭代这个列表,不仅给出了每个迭代的当前元素,还给出了当前元素之前和之后的元素。这可能是一个Tuple3但不是必需的。这可能是元组签名:

(Option[T], T, Option[T])

为了澄清我的意思,这是List[String]上每次迭代的拟议元组,在第四次之后结束。

迭代1:(None, "foo", Some("bar"))

迭代2:(Some("foo"), "bar", Some("baz"))

迭代3:(Some("bar"), "baz", Some("blah"))

迭代4:(Some("baz"), "blah", None)

我怎么能达到这样的结果?再说一遍:我不受Tuple3的约束,任何其他解决方案也非常感谢!

谢谢!

3 个答案:

答案 0 :(得分:16)

这是一种方法。它使用新的Scala 2.8集合方法sliding

def window[A](l: List[A]): Iterator[List[Option[A]]] = 
   (None :: l.map(Some(_)) ::: List(None)) sliding 3

window(List(1, 2, 3, 4, 5)).toList

// List(List(None, Some(1), Some(2)), List(Some(1), Some(2), Some(3)), List(Some(2), Some(3), Some(4)), List(Some(3), Some(4), Some(5)), List(Some(4), Some(5), None))

更新:这是一个适用于Streams的版本。

def windowS[A](s: Stream[A]): Stream[List[Option[A]]] = 
  (None #:: s.map(Some(_): Option[A]) #::: Stream(None: Option[A])).sliding(3).toStream.map(_.toList)  

val posInts = Stream.range(1, Integer.MAX_VALUE)
windowS(posInts).take(5).toList

答案 1 :(得分:3)

如果你使用2.8,那么

Retronym的答案会很好。如果您使用的是2.7.x,则没有出色的库存解决方案,但您可以轻松构建自己的解决方案。例如,如果您只想要存在之前和之后的三元组,您可以执行以下操作:

class Tuple3Iterator[T](solo: Iterator[T]) extends Iterator[(T,T,T)] {
  var current = if (solo.hasNext) Some(solo.next) else None
  var future = if (solo.hasNext) Some(solo.next) else None
  def hasNext = solo.hasNext
  def next = {
    val past = current
    current = future
    future = Some(solo.next)
    (past.get,current.get,future.get)
  }
}
class IteratorToT3[T](it: Iterator[T]) {
  def treble = new Tuple3Iterator[T](it)
}
implicit def allowTrebling[T](it: Iterable[T]) = new IteratorToT3[T](it.elements)

scala> List("Hi","there",5,"you").treble.foreach(println(_))         
(Hi,there,5)
(there,5,you)

如果您希望在保留选项之前和之后允许,(编辑:我之前没有给出完整或无错误的更改集),请改为使用

class Tuple3Iterator[T](solo: Iterator[T]) extends Iterator[(Option[T],T,Option[T])] {
  var current = None:Option[T]
  var future = if (solo.hasNext) Some(solo.next) else None
  def hasNext = (solo.hasNext || future!=None)
  def next = {
    val past = current
    current = future
    future = if (solo.hasNext) Some(solo.next) else None
    (past,current.get,future)
  }
}

scala> List("Hi","there",5,"you").treble.foreach(println(_))
(None,Hi,Some(there))
(Some(Hi),there,Some(5))
(Some(there),5,Some(you))
(Some(5),you,None)

答案 2 :(得分:2)

当然,最好使用Scala 2.8和retronym's solution,但这是我对Scala 2.7的解决方案:

class MyIterator[T](l: List[T]) extends Iterator[(Option[T],T,Option[T])] {
  var last: Option[T] = None
  var curr = l
  def hasNext = !curr.isEmpty
  def next = {
    val t = curr match {
      case first :: second :: tail => (last, first, Some(second))
      case first :: Nil => (last, first, None)
      case Nil => throw new java.util.NoSuchElementException
    }
    last = Some(curr.head)
    curr = curr.tail
    t
  }
}