Подтвердить что ты не робот

Внедрить DISTINCT для понимания

В предпоследней лекции своего курса Курсера профессор Одерский предложил следующее понимание for в качестве заключительного шага в прекрасном тематическом исследовании:

def solutions(target: Int): Stream[Path] =
  for {
    pathSet <- pathSets
    path <- pathSet
    if path.endState contains target
  } yield path

В более ранней лекции он сделал несколько аналогий между for пониманиями и SQL.

Я ищу способ yield только те path, которые имеют DISTINCT endState.

Есть ли способ вернуться в рамках предложения фильтра того же понимания к элементам, которые уже были получены?

Другим подходом может быть преобразование pathSets в Map от endState до path перед оператором for, а затем вернуть его обратно в Stream перед его возвратом. Тем не менее, это, казалось бы, потеряло бы ленивые вычислительные преимущества использования Stream.

Более ранний метод из одного и того же примера исследования выполнил аналогичные цели, но он уже был рекурсивной функцией, в то время как этот (как представляется, не нужен) должен быть рекурсивным.

Похоже, я мог использовать mutable Set для отслеживания endState, которые получают доход, но это неудовлетворительно, так как курс успешно избегал использования изменчивости.

4b9b3361

Ответ 1

Есть ли способ вернуться в рамках предложения фильтра того же понимания к элементам, которые уже были получены?

Твой для понимания десугаров к чему-то более-менее нравится

pathSets flatMap {
  pathSet => pathSet filter {
   path => path.endState contains target
  }
} map {path => path}

Последнее отображение с функцией идентификации - это ваш доход. Я не могу вспомнить, позволяет ли спецификация разрешить эту карту, когда она является функцией идентификации.

В любом случае, я надеюсь, что это станет более ясным, почему нет "возврата" к этой структуре.

Вы можете написать ленивую, рекурсивную функцию отличной функции

implicit class DistinctStream[T](s: Stream[T]) {
  def distinctBy[V](f: T => V): Stream[T] = {
    def distinctBy(remainder: Stream[T], seen:Set[V]): Stream[T] =
      remainder match {
        case head #:: tail => 
          val value = f(head)
          if (seen contains value) distinctBy(tail, seen)
          else Stream.cons(head, distinctBy(tail, seen + value))
        case empty => empty
     }

    distinctBy(s, Set())  
  }
}

И используйте его так

def solutions(target: Int): Stream[Path] =
(for {
 pathSet <- pathSets
 path <- pathSet
 if path.endState contains target
} yield path) distinctBy (_.endState)

Да, теперь есть рекурсия. Но уже существовало то, что функции Stream map, flatMap и filter теперь все ленивые рекурсивные функции.