我有以下数据结构
val list = List(1,2,
List(3,4),
List(5,6,7)
)
我希望得到这个结果
List(
List(1,2,3,5), List(1,2,3,6), List(1,2,3,7),
List(1,2,4,5), List(1,2,4,6), List(1,2,4,7)
)
输入中的子列表数量和元素数量可能会有所不同
P.S。
我正在尝试将此作为第一步
list.map{
case x => List(x)
case list:List => list
}
和一些理解,但它不起作用,因为我不知道结果的每个子列表将有多少元素
答案 0 :(得分:3)
在Scala中最常避免使用类似List[Any]
的类型 - 语言的大部分功能来自其智能类型系统,而这种类型阻碍了这一点。因此,您将列表转换为规范化List[List[Int]]
的直觉就是:
val normalizedList = list.map {
case x: Int => List(x)
case list: List[Int @unchecked] => list
}
请注意,如果list
包含除List
以外的某种类型的Int
,例如List[String]
,则由于类型擦除,这最终会引发运行时异常。这正是未能使用强类型时出现的问题!您可以阅读有关处理类型擦除的策略的更多信息here。
获得标准化List[List[Int]]
后,您可以使用foldLeft
来构建组合。你也明白for
理解在这里可以很好地运作:
normalizedList.foldLeft(List(List.empty[Int])) { (acc, next) =>
for {
combo <- acc
num <- next
} yield (combo :+ num)
}
在foldLeft
的每次迭代中,我们会考虑next
中的另一个子列表(normalizedList
)。我们查看到目前为止构建的每个组合(combo
中的每个acc
),然后对于num
中的每个数字next
,我们通过将其附加到{{ {1}}。
正如您现在所做的那样,combo
理解对于for
,map
和flatMap
操作来说确实是语法糖。所以我们也可以用那些更原始的方法来表达这个:
filter
您甚至可以使用normalizedList.foldLeft(List(List.empty[Int])) { (acc, next) =>
acc.flatMap { combo =>
next.map { num => combo :+ num }
}
}
的{{1}}别名,切换地图的顺序,并使用下划线语法以获得最终简洁:
:/
答案 1 :(得分:0)
val list = List(1,2,
List(3,4),
List(5,6,7)
)
def getAllCombinations(list: List[Any]) : List[List[Int]] ={
//normalize head so it is always a List
val headList: List[Int] = list.head match {
case i:Int => List(i)
case l:List[Int] => l
}
if(list.tail.nonEmpty){
// recursion for tail combinations
val tailCombinations : List[List[Int]] = getAllCombinations(list.tail)
//combine head combinations with tail combinations
headList.flatMap(
{i:Int => tailCombinations.map(
{l=>List(i).++(l)}
)
}
)
}
else{
headList.map(List(_))
}
}
print(getAllCombinations(list))
答案 2 :(得分:0)
这也可以通过使用foldLeft来实现。在下面的代码中,通过将每个当前列表与每个新项目组合,将外部列表的每个项目折叠到列表列表中。
val list = List(1,2, List(3,4), List(5,6,7) )
val lxl0 = List( List[Int]() ) //start value for foldLeft
val lxl = list.foldLeft( lxl0 )( (lxl, i) => {
i match {
case i:Int => for( l <- lxl ) yield l :+ i
case newl:List[Int] => for( l <- lxl;
i <- newl ) yield l :+ i
}
})
lxl.map( _.mkString(",") ).foreach( println(_))
虽然我没有使用您想要的地图,但我相信可以更改代码以执行地图并使所有元素列出[Int]。然后,这可以简化foldLeft以简化for-comprehension。但是,我无法立即开始工作;)