Scala - для: несоответствие типов - PullRequest
0 голосов
/ 03 ноября 2018

Вот структура: - Точки - сегменты - дорожки

case class Point(name: String, x: Long, y: Long)

case class Segment(from: Point, to: Point)

case class Path(segments: Vector[Segment])

Я пытаюсь найти все возможные пути из списка доступных сегментов, чтобы соединить две точки (от и до). Вот моя функция:

def allPossiblePaths(segments: Vector[Segment], from: Point, to: Point) : Option[Vector[Path]] = {

    if (from == to) Option(Vector())

    for {
      segment <- segments.filter(segment => segment.from == from)
      nextSegment <- segments.filter(segmentSuivant => segmentSuivant.from == segment.to)
      if nextSegment.to != segment.from
    } yield allPossiblePaths(segments.filter(segment => segment.from == from) ,segment.to, nextSegment.to)


  }

Если я попытаюсь:

allPossiblePaths(topSegments, tl, tr)

с:

val tl = Point("tl", 0, -10)
  val t  = Point("t", 0, 0)
  val tr = Point("tr", 0, 10)


  // tl - t - tr
  //  |   |    |
  // bl - b --- br


  // Segments

  val tlt     = Segment(tl, t)
  val tlbl     = Segment(tl, bl)
  val tb     = Segment(t, b)
  val ttr     = Segment(t, tr)      

  val topSegments = Vector(tlt, ttr, bbr)

У меня есть эта ошибка:

 Error:(63, 15) type mismatch;
 found   : scala.collection.immutable.Vector[Option[Vector[chemins.Path]]]
 required: Option[Vector[chemins.Path]]
      segment <- segments.filter(segment => segment.from == from)

Но когда я делаю

for {
          segment <- segments.filter(segment => segment.from == from)
}

Я использую for для вектора [сегмента], поэтому не понимаю, почему появляется «scala.collection.immutable.Vector»

Заранее спасибо!

Редактировать 1

Введен класс "PathList":

case class PathList(paths: Vector[Path])

Изменен код с добавлением "else" и "some"

  def allPossiblePaths(segments: Vector[Segment], from: Point, to: Point) : Option[PathList] = {

    if (from == to) Some(PathList(Vector()))

    else {

      for {
        segment <- segments.filter(segment => segment.from == from)
        nextSegment <- segments.filter(segmentSuivant => segmentSuivant.from == segment.to)
        if nextSegment.to != segment.from
      } yield allPossiblePaths(segments.filter(segment => segment.from == from), segment.to, nextSegment.to)

    }


  }

Ошибка на самом деле не изменилась:

Error:(65, 17) type mismatch;
 found   : scala.collection.immutable.Vector[chemins.PathList]
 required: chemins.PathList
        segment <- segments.filter(segment => segment.from == from)

Редактировать 2

Пытался не указывать тип возврата, и он компилируется

def allPossiblePaths( segments: Vector[Segment], from: Point, to: Point) {

    if (from == to) Path(Vector())

    else {

      for {
        segment <- segments.filter(segment => segment.from == from)
        nextSegment <- segments.filter(segmentSuivant => segmentSuivant.from == segment.to)
        if nextSegment.to != segment.from
      } yield allPossiblePaths(segments.filter(segment => segment.from == from), segment.to, nextSegment.to)
    }

  }

возвращается:

Expected :Some(Path(Vector(Segment(Point(tl,0,-10),Point(t,0,0)), Segment(Point(t,0,0),Point(b,10,0)), Segment(Point(b,10,0),Point(br,10,20)))))
Actual   :<(), the Unit value>

Ну, результат не тот, что я ожидал, но это что-то, я думаю

1 Ответ

0 голосов
/ 05 ноября 2018

Я думаю, что иногда бывает полезно немного обобщить при решении подобных проблем. Рассмотрим функцию ниже:

def pathsFrom[S, A](z: S)(f: S => Stream[(S, A)]): Stream[(S, List[A])] = {

  def go(initial: Stream[(S, List[A], Set[S])]): Stream[(S, List[A])] =
    initial match {
      case (s, as, explored) #:: tail =>
        val neighbors = f(s)
        val newNeighbors = neighbors
          .filter { case (s, _) => !explored.contains(s) }
          .map { case (s, a) => (s, a :: as, explored + s) }
        ((s, as)) #:: go(tail #::: newNeighbors)
      case _ => Stream.empty
    }

  go(Stream((z, Nil, Set(z))))
}

Это воплощение обобщенного алгоритма, который начинается с некоторого начального состояния S и функции перехода f, которая при заданном состоянии S возвращает Stream[(S, A)] всех состояний S, непосредственно достижимых из этого состояния, вместе с связанные ходы A. Затем он возвращает Stream[(S, List[A])] всех путей из начального состояния и связанных с ним конечных состояний.

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

def next(point: Point)(segments: List[Segment]): Stream[(Point, Segment)] =
  segments.filter(_.from == point).map(segment => (segment.to, segment)).toStream

Затем вы можете просто отфильтровать состояния, заканчивающиеся в желаемой конечной точке:

pathsFrom(tl)(next(_)(segments))
  .filter(_._1 == br)
  .map(_._2.reverse)
  .toList
  .foreach(println)

Если предположить, что вы описали шесть точек и сегменты, идущие сверху вниз и слева направо между соседними точками, это вернет:

List(Segment(Point(tl,0,-10),Point(t,0,0)), Segment(Point(t,0,0),Point(tr,0,10)), Segment(Point(tr,0,10),Point(br,-10,10)))
List(Segment(Point(tl,0,-10),Point(t,0,0)), Segment(Point(t,0,0),Point(b,-10,0)), Segment(Point(b,-10,0),Point(br,-10,10)))
List(Segment(Point(tl,0,-10),Point(bl,-10,-10)), Segment(Point(bl,-10,-10),Point(b,-10,0)), Segment(Point(b,-10,0),Point(br,-10,10)))

Другими словами, чтобы перейти сверху вниз, вправо, мы можем перейти вправо / вправо / вниз, вправо / вниз / вправо или вниз / вправо / вправо.

...