【发布时间】:2012-02-02 13:42:27
【问题描述】:
我想从一个列表中生成所有可能的对,限制为 (a,b) == (b,a) 和 ((a,b),(c,d)) = = ((c,d),(a,b)) 对于所有 a、b、c、d。此外,我可以假设我作为参数提供的列表中的所有元素都是不同的。
我做的第一件事就是写下这个列表理解:
pairsOfPairs :: [a] -> [((a,a),(a,a))]
pairsOfPairs xs = [((w,x),(y,z)) | w <- xs, x <- xs, y <- xs, z <- xs,
w < x, y < z, w < y, w /= z, x /= y, x /= z]
这具有惯用的优点,但速度很慢(分析表明,接近 90% 的运行时间都花在了这个函数和另一个类似的函数上)。
缓慢的原因是,对于一个包含 n 个元素的列表,它会生成 n^4 对候选对,但限制最终将其缩减为 n!/(8 * (n-4)!),这意味着我们至少做了 8 倍的工作量。
有没有办法重写函数pairsOfPairs 来提高速度?显然它仍然是 O(n^4),但我希望降低常数。
编辑:事实上,我几乎总是用长度为 5 的列表来调用这个函数,这意味着结果中有 5!/8 = 15 个元素,但是该函数会生成一个5^4 = 625 个元素作为中间步骤。如果我能消除所有这些中间元素,我将因此获得大约 40 倍的加速!
【问题讨论】:
-
您的第一段似乎暗示a = b = c = d。我不认为这就是你的意思。
-
@dave4420 我使用 '==' 来表示等价,即 (a,b) 对应被视为与 (b,a) 对等价,但不是 a 和b 必须相等。
标签: optimization haskell profiling