Scala: фильтрация списка кортежей для получения nonEmptyList - PullRequest
2 голосов
/ 18 апреля 2019

У меня есть список типа List[(A, List[B])].Я хочу сгладить эту структуру и получить:

  • NonEmptyList[A], состоящий из всех A, соответствующих nonEmpty List[B].

  • все эти B скомбинированы: NonEmptyList[B]

т.е. я хочу получить Option[(NonEmptyList[A], NonEmptyList[B])].Какой самый краткий способ сделать это.

Ответы [ 2 ]

2 голосов
/ 18 апреля 2019

Не проверено, но с использованием определений из комментариев, это должно работать:

for {
  a <- NonEmptyList.fromList(list.collect{ case (a, _::_) => a })
  b <- NonEmptyList.fromList(list.flatMap(_._2))
} yield (a, b)

Это также имеет то преимущество, что избегает второго вычисления, если первое возвращает None.


Предыдущие версии:

val listA = list.collect{ case (a, _::_) => a }
val listB = list.flatMap(_._2)

listA.headOption.flatMap(listB.headOption.map(_ => (NonEmptyList(listA), NonEmptyList(listB))))

Другая версия может быть

(listA, listB) match {
  case (_::_, _::_) =>
    Some(NonEmptyList(listA), NonEmptyList(listB))
  case _ =>
    None
}
1 голос
/ 18 апреля 2019

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

def flat[A,B](list: List[(A, List[B])]): Option[(NonEmptyList[A], NonEmptyList[B])] = {

    @tailrec
    def collapse(list: List[(A, List[B])], as: List[A], bs: List[B]): (List[A], List[B]) = {
      list match {
        case (a,b) :: xs => collapse(xs, a :: as, b ++ bs)
        case Nil => (as, bs)
      }
    }

    collapse(list, Nil, Nil) match {
      case (a :: ax, b :: bx) => Some((NonEmptyList(a, ax), NonEmptyList(b, bx)))
      case _ => None
    }

}

Другой вариант - использовать unzip:

def flat2[A,B](list: List[(A, List[B])]) = list.unzip match {
   case (as,bs) => (as, bs.flatten)  match {
      case (a :: ax, b :: bx) => Some((NonEmptyList(a, ax), NonEmptyList(b, bx)))
      case _ => None
   }
}

Результат:

flat(List((1, List("a", "b")), (2, List("a", "c")), (3, List("d", "e")), (4, List("x", "y"))))
//Some((NonEmptyList(4, 3, 2, 1),NonEmptyList(x, y, d, e, a, c, a, b)))
flat(List((1, List()), (2, List("a"))))
//Some((NonEmptyList(2, 1),NonEmptyList(a)))
flat(List((1, List()), (2, List())))
//None
flat(List())
//None
...