Scala 组合列表函数
下面的函数计算列表元素的可能组合Scala 组合列表函数,scala,Scala,下面的函数计算列表元素的可能组合 (1, 2), (1, 3), (1, 4) 不返回列表中相同的元素,也只返回唯一的元素: def combinations[T](l: List[T]): List[(T,T)] = l match { case Nil => Nil case h::Nil => Nil case h::t => t.map(x=>(h,x)) ++ combinations(t) } 列表(1,2,3)返回列表((1,2)
(1, 2), (1, 3), (1, 4)
不返回列表中相同的元素,也只返回唯一的元素:
def combinations[T](l: List[T]): List[(T,T)] = l match {
case Nil => Nil
case h::Nil => Nil
case h::t => t.map(x=>(h,x)) ++ combinations(t)
}
列表(1,2,3)返回列表((1,2)、(1,3)、(2,3))
这个解决方案(不是我的)很优雅,但我想知道它背后的直觉。代码中包含的列表元素是否有我不知道的通用属性?我知道这个解决方案为什么有效,但我不确定如何实现这个解决方案?当您考虑如何手动构建所有组合时,这实际上是非常直观的。例如,以
列表(1、2、3、4)
为例。为了有条不紊地创建所有组合,我将获取列表中的第一个元素1
,然后将其与所有剩余元素组合
(1, 2), (1, 3), (1, 4)
这些都是包含1
的可能组合。现在,让我们找到所有包含2
的组合,但不需要包含那些包含1
的组合,因为我们已经有了它们。这意味着我们将使用列表中其余元素的组合
(2, 3), (3, 4)
然后使用3
:
(3, 4)
你看到图案了吗?我们获取列表的第一个元素,然后将其与列表的所有剩余元素(尾部)配对。这就是代码的这一部分:
case h :: t => t.map(x => (h, x))
// 1 :: List(2, 3, 4) => List((1, 2), (1, 3), (1, 4))
然后我们移动到列表的下一个元素,并执行相同的操作。这是递归步骤:++compositions(t)
,并使用++
聚合结果
如果我们从1
开始,那么在封面下的第一个递归调用是组合(列表(2,3,4))
,我们重复以下逻辑:
case h :: t => t.map(x => (h, x))
// 2 :: List(3, 4) => List((2, 3), (3, 4))
最后:
case h :: t => t.map(x => (h, x))
// 3 :: List(4) => List((3, 4))
因此,我们用List((1,2),(1,3),(1,4))+++List((2,3),(3,4))+++List((3,4))
当然,在其他情况下,如果有零个或一个元素,就不能产生更多的组合:
case Nil => Nil
case h :: Nil => Nil
正如@0_uuuu所述,h::Nil
实际上可以由h::t
处理,因为我们将有:
case h :: t => t.map(x => (h, x)) ++ combinations(t)
// ^ Nil ^ Nil maps to Nil ^ Will hit the first case on the next call, which is also Nil
当您考虑如何手动构建所有组合时,这实际上是非常直观的。例如,以
列表(1、2、3、4)
为例。为了有条不紊地创建所有组合,我将获取列表中的第一个元素1
,然后将其与所有剩余元素组合
(1, 2), (1, 3), (1, 4)
这些都是包含1
的可能组合。现在,让我们找到所有包含2
的组合,但不需要包含那些包含1
的组合,因为我们已经有了它们。这意味着我们将使用列表中其余元素的组合
(2, 3), (3, 4)
然后使用3
:
(3, 4)
你看到图案了吗?我们获取列表的第一个元素,然后将其与列表的所有剩余元素(尾部)配对。这就是代码的这一部分:
case h :: t => t.map(x => (h, x))
// 1 :: List(2, 3, 4) => List((1, 2), (1, 3), (1, 4))
然后我们移动到列表的下一个元素,并执行相同的操作。这是递归步骤:++compositions(t)
,并使用++
聚合结果
如果我们从1
开始,那么在封面下的第一个递归调用是组合(列表(2,3,4))
,我们重复以下逻辑:
case h :: t => t.map(x => (h, x))
// 2 :: List(3, 4) => List((2, 3), (3, 4))
最后:
case h :: t => t.map(x => (h, x))
// 3 :: List(4) => List((3, 4))
因此,我们用List((1,2),(1,3),(1,4))+++List((2,3),(3,4))+++List((3,4))
当然,在其他情况下,如果有零个或一个元素,就不能产生更多的组合:
case Nil => Nil
case h :: Nil => Nil
正如@0_uuuu所述,h::Nil
实际上可以由h::t
处理,因为我们将有:
case h :: t => t.map(x => (h, x)) ++ combinations(t)
// ^ Nil ^ Nil maps to Nil ^ Will hit the first case on the next call, which is also Nil
使用
列表定义函数/递归解决方案时,最简单的方法是涵盖发生的基本情况。然后定义部分解决方案并将它们添加到一起
您希望在输出中有成对的元素,因此您首先会发现,对于空列表(Nil
)或仅包含单个元素(h::Nil
)的列表,没有部分解决方案,因此这两种情况的结果是Nil
。最后一种情况是头部元素h
和非空尾部。因此,使用map
函数为每个尾部元素生成所有h
对,并对尾部递归重复
请注意,从技术上讲,中间的情况是不相关的。以下几点就足够了:
def combinations[A](xs: List[A]): List[(A, A)] = xs match {
case Nil => Nil
case h :: t => t.map(h -> _) ++ combinations(t)
}
使用列表定义函数/递归解决方案时,最简单的方法是涵盖发生的基本情况。然后定义部分解决方案并将它们添加到一起
您希望在输出中有成对的元素,因此您首先会发现,对于空列表(Nil
)或仅包含单个元素(h::Nil
)的列表,没有部分解决方案,因此这两种情况的结果是Nil
。最后一种情况是头部元素h
和非空尾部。因此,使用map
函数为每个尾部元素生成所有h
对,并对尾部递归重复
请注意,从技术上讲,中间的情况是不相关的。以下几点就足够了:
def combinations[A](xs: List[A]): List[(A, A)] = xs match {
case Nil => Nil
case h :: t => t.map(h -> _) ++ combinations(t)
}
问题是什么?要解释为什么会这样?@0\uuuu请查看更新问题是什么?要解释为什么会这样?@0\uuuu请查看更新