Несколько выходов в понимании последовательности? - PullRequest
3 голосов
/ 18 июля 2010

Я пытаюсь выучить Scala и попытался написать понимание последовательности, которое извлекает из последовательности униграммы, биграммы и триграммы. Например, [1,2,3,4] следует преобразовать в (не синтаксис Scala)

[1; _,1; _,_,1; 2; 1,2; _,1,2; 3; 2,3; 1,2,3; 4; 3,4; 2,3,4]

В Scala 2.8 я пробовал следующее:

def trigrams(tokens : Seq[T]) = {
  var t1 : Option[T] = None
  var t2 : Option[T] = None
  for (t3 <- tokens) {
    yield t3
    yield (t2,t3)
    yield (t1,t2,Some(t3))
    t1 = t2
    t2 = t3
  }
}

Но это не компилируется, поскольку, , по-видимому, , только один yield допускается в for -компонентности (без операторов блока) Есть ли какой-нибудь другой элегантный способ получить такое же поведение, используя только один проход для данных?

Ответы [ 5 ]

7 голосов
/ 18 июля 2010

Вы не можете иметь несколько выходов в цикле for, потому что циклы for являются синтаксическим сахаром для операций карты (или flatMap):

for (i <- collection) yield( func(i) )

переводится в

collection map {i => func(i)}

Без дохода вообще

for (i <- collection) func(i)

переводится в

collection foreach {i => func(i)}

Таким образом, все тело цикла for превращается в одно замыкание, и наличие ключевого слова yield определяет, будет ли функция, вызываемая для коллекции, map или foreach (или flatMap ). Из-за этого перевода запрещено следующее:

  1. Использование императивных выражений рядом с yield для определения того, что будет получено.
  2. Использование нескольких выходов

(Не говоря уже о том, что предложенная вами версия вернет List[Any], потому что кортежи и 1-грамм относятся к разным типам. Возможно, вы захотите получить List[List[Int]] вместо этого)

Попробуйте вместо этого следующее (в котором n-граммы располагаются в порядке их появления):

val basis = List(1,2,3,4)
val slidingIterators = 1 to 4 map (basis sliding _)

for {onegram <- basis
     ngram <- slidingIterators if ngram.hasNext}
     yield (ngram.next)

или

val basis = List(1,2,3,4)
val slidingIterators = 1 to 4 map (basis sliding _)
val first=slidingIterators head
val buf=new ListBuffer[List[Int]]

while (first.hasNext)
   for (i <- slidingIterators)
      if (i.hasNext)
         buf += i.next

Если вы предпочитаете, чтобы n-граммы были в порядке длины, попробуйте:

val basis = List(1,2,3,4)
1 to 4 flatMap { basis sliding _ toList }
2 голосов
/ 18 июля 2010
scala> val basis = List(1, 2, 3, 4)
basis: List[Int] = List(1, 2, 3, 4)

scala> val nGrams = (basis sliding 1).toList ::: (basis sliding 2).toList ::: (basis sliding 3).toList
nGrams: List[List[Int]] = ...

scala> nGrams foreach (println _)
List(1)
List(2)
List(3)
List(4)
List(1, 2)
List(2, 3)
List(3, 4)
List(1, 2, 3)
List(2, 3, 4)
1 голос
/ 18 июля 2010

Вы можете попробовать функциональную версию без заданий:

def trigrams[T](tokens : Seq[T]) = {
  val s1 = tokens.map { Some(_) }
  val s2 = None +: s1
  val s3 = None +: s2
  s1 zip s2 zip s3 map {
    case ((t1, t2), t3) => (List(t1), List(t1, t2), List(t1, t2, t3))
  }
}
1 голос
/ 18 июля 2010
val basis = List(1, 2, 3, 4)
val nGrams = basis.map(x => (x)) ::: (for (a <- basis; b <- basis) yield (a, b)) ::: (for (a <- basis; b <- basis; c <- basis) yield (a, b, c))
nGrams: List[Any] = ...
nGrams foreach (println(_))
1
2
3
4
(1,1)
(1,2)
(1,3)
(1,4)
(2,1)
(2,2)
(2,3)
(2,4)
(3,1)
(3,2)
(3,3)
(3,4)
(4,1)
(4,2)
(4,3)
(4,4)
(1,1,1)
(1,1,2)
(1,1,3)
(1,1,4)
(1,2,1)
(1,2,2)
(1,2,3)
(1,2,4)
(1,3,1)
(1,3,2)
(1,3,3)
(1,3,4)
(1,4,1)
(1,4,2)
(1,4,3)
(1,4,4)
(2,1,1)
(2,1,2)
(2,1,3)
(2,1,4)
(2,2,1)
(2,2,2)
(2,2,3)
(2,2,4)
(2,3,1)
(2,3,2)
(2,3,3)
(2,3,4)
(2,4,1)
(2,4,2)
(2,4,3)
(2,4,4)
(3,1,1)
(3,1,2)
(3,1,3)
(3,1,4)
(3,2,1)
(3,2,2)
(3,2,3)
(3,2,4)
(3,3,1)
(3,3,2)
(3,3,3)
(3,3,4)
(3,4,1)
(3,4,2)
(3,4,3)
(3,4,4)
(4,1,1)
(4,1,2)
(4,1,3)
(4,1,4)
(4,2,1)
(4,2,2)
(4,2,3)
(4,2,4)
(4,3,1)
(4,3,2)
(4,3,3)
(4,3,4)
(4,4,1)
(4,4,2)
(4,4,3)
(4,4,4)
1 голос
/ 18 июля 2010

Полагаю, мне следовало подумать об этом.

def trigrams(tokens : Seq[T]) : Seq[(Option[T],Option[T],T)] = {
  var t1 : Option[T] = None
  var t2 : Option[T] = None
  for (t3 <- tokens)
    yield {
      val tri = (t1,t2,t3)
      t1 = t2
      t2 = Some(t3)
      tri
    }
}

Затем извлеките униграммы и биграммы из триграмм. Но может ли кто-нибудь объяснить мне, почему «мульти-доходность» не разрешена, и есть ли другой способ добиться их эффекта?

...