List 根据scala中的元素类型将列表拆分为子列表
如何根据元素类型将列表拆分为子列表 简言之,鉴于:List 根据scala中的元素类型将列表拆分为子列表,list,scala,List,Scala,如何根据元素类型将列表拆分为子列表 简言之,鉴于: trait Drink final case object Coke extends Drink final case object Pepsi extends Drink val drinks = List(Coke,Coke,Pepsi,Coke,Pepsi,Pepsi) 我想: List( List(Coke,Coke), List(Pepsi), List(Coke), List(Pepsi, Pepsi) ) 有些冗长,部分原因
trait Drink
final case object Coke extends Drink
final case object Pepsi extends Drink
val drinks = List(Coke,Coke,Pepsi,Coke,Pepsi,Pepsi)
我想:
List( List(Coke,Coke), List(Pepsi), List(Coke), List(Pepsi, Pepsi) )
有些冗长,部分原因是它们是case对象。为什么不在列表中只使用
groupBy
val rows = drinks.groupBy(x => x).values.toList
可以测试您可以使用短尾递归函数,如下所示 其思想是使用
next
将“要附加到结果的下一个饮料列表”和acc
将这些饮料列表累积到一个饮料列表中
基本情况是一个空列表,其中返回结果。否则,要么下一个饮料匹配下一个子列表(将其添加到此子列表),要么不匹配(将子列表添加到结果中,并使用新饮料启动新的子列表)
请注意,:+
是一个列表方法,它返回一个新列表,并附加指定的项
@tailrec
def获取(列表:列表[饮料],
下一步:List[Drink]=List(),
acc:List[List[Drink]=List()):List[List[Drink]]=
列表匹配{
案例Nil=>acc:+next//dump最终结果
案例头部::尾部=>
if(next.isEmpty | | next.head.getClass==head.getClass)get(tail,next:+head,acc)
else get(尾部、列表(头部)、acc:+next)
}
println(获取(饮料))
结果:
List(List(Coke, Coke), List(Pepsi), List(Coke), List(Pepsi, Pepsi))
注意,注意jwvh也有一个正确的答案,使用正确的模式匹配而不是这些条件。在列表中使用head
方法可能不安全(或者编译器很难确定安全性),但这种方法可能更简洁,尤其是在有多种饮料的情况下
如果您想避免直接使用head
,可以这样写,我发现这更让人困惑:
。。。
if(next.headOption.map(h=>h.getClass==head.getClass).getOrElse(true))get(tail,next:+head,acc)
...
如果类型是参数化的,则需要注释中提到的TypeTags
。。。但在这一点上,只需在类本身中添加一个方法就很容易了。。。比如:
class Drink[T: ClassTag] {
def typeId = s"Drink of ${classTag[T].runtimeClass.getName}"
}
然后,您就可以比较这些类型ID而不是实际的类。您想要一些泛型的东西,还是对一组特定类型的解决方案满意?此外,它们是否始终是case对象,或者也可能是case类最后,你试过什么?@LuisMiguelMejíaSuárez这套特殊的类型是不相关的。现实世界将是案例类。这些案例类将是参数化/泛型的吗?类似于
最终案例类Foo[T](数据:T)扩展了Bar
?如果是这样的话,你有列表(Foo(1),Foo(“3”))
这两个是在同一组还是在不同的组中?是的,当然,我只是没有将它们参数化以简化问题。那么,由于类型擦除,你的问题基本上无法解决。-你有四个选择:1。简化数据类型,以避免类型擦除-2。只依赖于类测试,这意味着Foo(1)
和Foo(“3”)
将属于同一组-3。使用TypeTags,但这需要创建列表的人用其TypeTag对每个元素进行压缩。-4.与上一个类似,创建自己的类型
ADT,并在创建列表时使用其类型
压缩每个元素。这不是OP要求的,它甚至只适用于案例对象
drinks.foldRight[List[List[Drink]](List.empty) {
case (next, (l@(last :: _) :: tail) if next.getClass == last.getClass =>
(next :: l)::tail
case (next, rest) => List(next) :: rest
}
class Drink[T: ClassTag] {
def typeId = s"Drink of ${classTag[T].runtimeClass.getName}"
}