Scala:过滤元组列表以获得非空列表
Scala: filtering list of tuples to get a nonEmptyList
我有一个 List[(A, List[B])]
类型的列表。我想展平这个结构并得到:
NonEmptyList[A]
组成的所有A
对应一个nonEmptyList[B]
.
所有这些 B
加起来:NonEmptyList[B]
也就是说,我想要 Option[(NonEmptyList[A], NonEmptyList[B])]
。最简洁的方法是什么。
未经测试,但使用评论中的定义,这应该有效:
for {
a <- NonEmptyList.fromList(list.collect{ case (a, _::_) => a })
b <- NonEmptyList.fromList(list.flatMap(_._2))
} yield (a, b)
如果第一个 returns 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
}
您可以使用尾递归函数遍历列表,但它可能不是很简洁,但它可能比第二种解决方案更快,因为它只遍历列表一次。
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
我有一个 List[(A, List[B])]
类型的列表。我想展平这个结构并得到:
NonEmptyList[A]
组成的所有A
对应一个nonEmptyList[B]
.所有这些
B
加起来:NonEmptyList[B]
也就是说,我想要 Option[(NonEmptyList[A], NonEmptyList[B])]
。最简洁的方法是什么。
未经测试,但使用评论中的定义,这应该有效:
for {
a <- NonEmptyList.fromList(list.collect{ case (a, _::_) => a })
b <- NonEmptyList.fromList(list.flatMap(_._2))
} yield (a, b)
如果第一个 returns 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
}
您可以使用尾递归函数遍历列表,但它可能不是很简洁,但它可能比第二种解决方案更快,因为它只遍历列表一次。
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