2010-01-25 69 views
11

我以编程和优雅的方式编写特定的应用程序时遇到问题。我现在想这一段时间,但我不能找到一个“好”的解决了这个问题:在列表中迭代,返回当前,下一个和当前的元素

假设我有以下列表:

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,任何其他解决方案也非常感谢!

谢谢!

回答

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 
+0

我敢肯定,这有效,但我的斯卡拉版本似乎没有滑动定义。我正在使用2.8.0.Beta1-RC7,哪个版本需要使用滑动? – Malax 2010-01-25 20:27:43

+0

我正在使用2.8.0.Beta1-RC8 – retronym 2010-01-25 20:32:15

+0

似乎RC8是必需的,现在就可以使用。谢谢! :-) – Malax 2010-01-25 20:42:09

3

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) 
+0

即使我已经使用Scala 2.8,这是一个非常好的学习代码。感谢您的贡献! – Malax 2010-01-25 20:37:54

2

更好地使用Scala的2.8和retronym'ssolution,当然,但这里是我的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 
    } 
} 
相关问题