代码之家  ›  专栏  ›  技术社区  ›  Malax

遍历列表,返回当前、下一个和当前之前的元素

  •  11
  • Malax  · 技术社区  · 16 年前

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

    鉴于我有以下列表:

    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 回复  |  直到 16 年前
        1
  •  16
  •   retronym    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))
    

    更新 :这是适用于流的版本。

    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
    
        2
  •  3
  •   Community Mohan Dere    9 年前

    Retronym 如果你用的是2.8,答案会很好。如果您使用的是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)
    
        3
  •  2
  •   Community Mohan Dere    9 年前

    最好使用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
      }
    }
    
    推荐文章