Перейдем к списку, возвращая текущий, следующий и элемент до текущего

У меня возникли проблемы с написанием конкретного приложения в scala -сеском и изящном виде. Я пробовал это в течение некоторого времени, но я не могу найти "хорошее" решение этой проблемы:

Учитывая, что у меня есть следующий список:

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

Я хочу перечислить этот список, не только предоставив мне текущий элемент для каждой итерации, но и элемент до и после текущего элемента. Это может быть Tuple3, но не требуется. Это может быть сигнатура Tuple:

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

Чтобы прояснить, что я имею в виду, это предлагаемый Tuple для каждой итерации над a 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, любое другое решение также очень ценится!

Спасибо!

Ответ 1

Здесь один подход. Он использует новый метод сбора 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

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

Лучше использовать Scala 2.8 и решение , но это мое решение для 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
  }
}