[英]Haskell: finding tuples of elements that equal n
I am trying to write a function in Haskell that takes a list of integers and an integer n and finds all tuples that equal n. 我试图在Haskell中编写一个函数,该函数接受一个整数列表和一个整数n并找到等于n的所有元组。 So far I have an implementation that works
到目前为止,我有一个可行的实现
tuplesum :: (Eq b, Num b) => [b] -> b -> [(b, b)]
tuplesum xs n = [(x1,x2) | x1 <- xs, x2 <- xs, x1 + x2 == n, x1 <= x2]
so if I gave this function the input 所以如果我给这个功能输入
tuplesum [5,1,4,0,5,6,9] 10
the output is [(5,5),(5,5),(1,9),(4,6),(5,5),(5,5)]
However, I have 4 duplicates of the (5,5) solution. 输出为
[(5,5),(5,5),(1,9),(4,6),(5,5),(5,5)]
但是,我有(5的4个重复项,5)解决。 I would like the function to output [(5,5),(1,9),(4,6)]
but I cant figure out how to constrain tuples that have the same integers without removing it as a solution entirely. 我希望该函数输出
[(5,5),(1,9),(4,6)]
但我无法弄清楚如何约束具有相同整数的元组而不将其作为解决方案完全删除。
I have the impression that you are looking for a way to select two elements out of the list such that x1
is always located before x2
. 我的印象是,您正在寻找一种从列表中选择两个元素的方法,以使
x1
始终位于x2
之前 。
A common way to always let x2
iterate over the remainder of the list is by using tails :: [a] -> [[a]]
. 始终让
x2
遍历列表其余部分的常用方法是使用tails :: [a] -> [[a]]
。 For a list, tails
will generate a list of all tails of the list, starting with the list itself. 对于列表,
tails
将生成列表的所有尾部的列表,从列表本身开始。 For example: 例如:
Prelude Data.List> tails [1, 4, 2, 5]
[[1,4,2,5],[4,2,5],[2,5],[5],[]]
We can use this with pattern matching to select one element, and get a reference to the remaining element. 我们可以将其与模式匹配一起使用,以选择一个元素,并获得对其余元素的引用。 For example:
例如:
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]
Note that it is still possible to obtain duplicates here, for example if 5
would occur three times in the list, since in that case x1
can select the first 5
, and then x2
can select the second 5
as well as the last one. 请注意,这里仍然有可能获得重复项,例如,如果
5
次出现在列表中三次,因为在这种情况下x1
可以选择前5
,然后x2
可以选择第二个5
和最后一个。 We can make use of a uniqness filter like nub :: Eq a => [a] -> [a]
for this: 为此,我们可以使用诸如
nub :: Eq a => [a] -> [a]
的唯一性过滤器:
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]
Note that it is however still better to use tails
here, since it will increase performance, since we will simply generate a smaller amount of duplicates in the first place. 但是请注意,此处最好使用
tails
,因为这样可以提高性能,因为首先我们只是生成少量重复项。
The above algorithm is still O(n 2 ) , and not very fast. 上面的算法仍然是O(n 2 ) ,并且不是很快。 We can however solve the problem the other way around: we can first construct a
HashSet
of the elements, and the for each element x1
, check if n - x1
is a member, like: 但是,我们可以用另一种方法解决问题:首先可以构造元素的
HashSet
,对于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
But the runtime is still O(n 2 ) because of the nub
, we can however use a hashNub :: (Eq a, Hashable a) => [a] -> [a]
here: 但是由于
nub
,运行时仍然是O(n 2 ) ,但是我们可以在这里使用hashNub :: (Eq a, Hashable a) => [a] -> [a]
:
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 xs) xs
and then let it work with: 然后让它与:
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
Now it works in O(n log n) . 现在它可以在O(n log n)中工作 。
I just really liked your function tuplesum xs n = [(x1,x2) | x1 <- xs, x2 <- xs, x1 + x2 == n, x1 <= x2]
我真的很喜欢您的函数
tuplesum xs n = [(x1,x2) | x1 <- xs, x2 <- xs, x1 + x2 == n, x1 <= x2]
tuplesum xs n = [(x1,x2) | x1 <- xs, x2 <- xs, x1 + x2 == n, x1 <= x2]
because it is a Cartesian product and it eliminates most symmetrical pairs that would otherwise constitute about half. tuplesum xs n = [(x1,x2) | x1 <- xs, x2 <- xs, x1 + x2 == n, x1 <= x2]
因为它是笛卡尔积,并且消除了大多数对称对,否则它们将构成大约一半。 It gets the predicate matches so very well. 谓词匹配非常好。 The only problem remaining is the duplicate elements.
剩下的唯一问题是重复元素。 I had forgotten about this until recently and Pg.
直到最近我和Pg都忘记了这一点。 86 of Graham Hutton 's "Programming in Haskell" and his
rmdups
function. 格雷厄姆·赫顿 ( Graham Hutton )的“在Haskell中编程 ”的86和他的
rmdups
功能。 What I like about his rmdups
is that it neither depends on imports. 我喜欢他的
rmdups
,因为它既不依赖进口。
rmdups :: Eq a => [a] -> [a]
rmdups [] = []
rmdups (x:xs) = x : filter (/= x) (rmdups xs)
Hutton's solution is wonderfully general and classically recursive. 赫顿的解决方案具有极好的通用性和经典递归性。 I did not want to post his solution here without adding something original so here is a list comprehension to eliminate duplicates of any data type including tuples.
我不想在不添加原始内容的情况下在这里发布他的解决方案,因此这里是一个列表理解功能,用于消除任何数据类型(包括元组)的重复项。
rmdups ls = [d|(z,d)<- zip [0..] ls, notElem d $ take z ls]
You can place either rmdups
function in front of your function rmdups.tuplesum
Your function eliminates most symmetrical pairs so rmdups
does not. 您可以将
rmdups
函数放置在函数rmdups.tuplesum
前面,函数可以消除大多数对称对,因此rmdups
不会。
rmdups [(5,5),(5,5),(1,9),(4,6),(5,5),(5,5)]
[(5,5),(1,9),(4,6)] [(5,5),(1,9),(4,6)]
Or 要么
rmdups "abcabcdefdef" OR "abcdefabcdef"
"abcdef" “ABCDEF”
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.