Haskell:找到等于n

时间:2018-04-11 20:01:32

标签: haskell

我试图在Haskell中编写一个函数,它接受一个整数列表和一个整数n,并找到所有等于n的元组。到目前为止,我有一个可行的实现

tuplesum :: (Eq b, Num b) => [b] -> b -> [(b, b)]
tuplesum xs n = [(x1,x2) | x1 <- xs, x2 <- xs, x1 + x2 == n, x1 <= x2]

所以如果我给这个函数输入

tuplesum [5,1,4,0,5,6,9] 10

输出是     [(5,5),(5,5),(1,9),(4,6),(5,5),(5,5)] 但是,我有(5,5)解决方案的4个重复。我希望函数输出[(5,5),(1,9),(4,6)],但是我无法弄清楚如何约束具有相同整数的元组而不将其完全删除。

2 个答案:

答案 0 :(得分:6)

元组生成中的对称性破坏

我的印象是,您正在寻找一种从列表中选择两个元素的方法,以便x1始终位于 x2之前

始终让x2遍历列表的其余部分的常用方法是使用tails :: [a] -> [[a]]。对于列表,tails将生成列表的所有尾部列表,从列表本身开始。例如:

Prelude Data.List> tails [1, 4, 2, 5]
[[1,4,2,5],[4,2,5],[2,5],[5],[]]

我们可以使用它与模式匹配来选择一个元素,并获得对剩余元素的引用。例如:

import Data.List(tails)

tuplesum :: (Eq b, Num b) => [b] -> b -> [(b, b)]
tuplesum xs n = [(x1,x2) | (x1:x2s) <- tails xs, x2 <- x2s, x1 + x2 == n]

请注意,此处仍然可以获取重复项,例如,如果5在列表中出现三次,那么x1可以选择第一个5,并且然后x2可以选择第二个5以及最后一个import Data.List(nub, tails) tuplesum :: (Eq b, Num b) => [b] -> b -> [(b, b)] tuplesum xs n = nub [(x1,x2) | (x1:x2s) <- tails xs, x2 <- x2s, x1 + x2 == n] 。我们可以使用像nub :: Eq a => [a] -> [a]这样的uniqness过滤器:

tails

请注意,在这里使用HashSet仍然更好,因为它会提高性能,因为我们首先会生成较少量的重复项。

使用哈希集获取&#34;其他&#34;元件

上述算法仍然是 O(n 2 ,并且速度不是很快。然而,我们可以反过来解决问题:我们可以先构造一个x1元素,并为每个元素n - x1,检查import Data.Hashable(Hashable) import Data.HashSet(fromList, member) tuplesum :: (Ord b, Hashable b, Num b) => [b] -> b -> [(b, b)] tuplesum xs n = nub [(x1,x2) | x1 <- xs, let x2 = n-x1, x1 <= x2, member x2 hs] where hs = fromList xs 是否是成员,如:< / p>

nub

但由于hashNub :: (Eq a, Hashable a) => [a] -> [a] hashNub = go HashSet.empty where go _ [] = [] go s (x:xs) = if x `HashSet.member` s then go s xs else x : go (HashSet.insert x s) xs ,运行时仍然是 O(n 2 ,我们可以在这里使用hashNub :: (Eq a, Hashable a) => [a] -> [a]

import Data.Hashable(Hashable)
import Data.HashSet(fromList, member)

tuplesum :: (Ord b, Hashable b, Num b) => [b] -> b -> [(b, b)]
tuplesum xs n = hashNub [(x1,x2) | x1 <- xs, let x2 = n-x1, x1 <= x2, member x2 hs]
    where hs = fromList xs

然后让它使用:

_registerServiceWorker() {
    if ('serviceWorker' in navigator) {

        window.addEventListener('load', function () {
            navigator.serviceWorker.register("../../content/js/app/service-worker.js", { scope: "/" }).then(function (registration) {
                console.log('Service worker registration succeeded:', registration);
            }).catch(function (error) {
                console.log('Service worker registration failed:', error);
            });;
        });
    }
}

现在它适用于 O(n log n)

答案 1 :(得分:0)

我真的很喜欢你的函数tuplesum xs n = [(x1,x2) | x1 <- xs, x2 <- xs, x1 + x2 == n, x1 <= x2]因为它是笛卡尔积,并且它消除了大多数对称的对,否则它们将构成大约一半。它很好地得到了谓词匹配。剩下的唯一问题是重复元素。直到最近我才忘记了这件事。 86. Graham Hutton &#39; &#34; Haskell编程&#34; 和他的rmdups函数。我喜欢他的rmdups是因为它既不依赖于进口。

rmdups :: Eq a => [a] -> [a]
rmdups [] = []
rmdups (x:xs) = x : filter (/= x) (rmdups xs)

Hutton的解决方案非常通用且经典递归。我不想在没有添加原始内容的情况下发布他的解决方案,所以这里是一个列表理解,以消除包括元组在内的任何数据类型的重复。

rmdups ls = [d|(z,d)<- zip [0..] ls, notElem d $ take z ls]

您可以将rmdups功能放在功能rmdups.tuplesum前面 你的函数消除了大多数对称对,因此rmdups没有。

rmdups [(5,5),(5,5),(1,9),(4,6),(5,5),(5,5)]

[(5,5),(1,9),(4,6)]

或者

rmdups "abcabcdefdef" OR "abcdefabcdef"

&#34; ABCDEF&#34;