[英]Pairing up elements from a list given a predicate
I'm relatively new to Haskell and found a challenge to create a set of tuples which greedily takes from a list given a predicate.我对 Haskell 比较陌生,发现创建一组元组的挑战,这些元组贪婪地从给定谓词的列表中获取。 For example, using
(\\x -> \\y -> odd(x+y))
on [2,3,4,5,6,7]
could return [(2,3),(3,2),(4,5),(5,4),(6,7),(7,6)]
or [(2,7),(6,5),(3,4),(4,3),(5,6),(7,2)]
or any other valid set of pairings, as long as it's one where each pair is symmetrical, and all items from the set are included in one and only one pairing.例如,在
[2,3,4,5,6,7]
上使用(\\x -> \\y -> odd(x+y))
可以返回[(2,3),(3,2),(4,5),(5,4),(6,7),(7,6)]
或[(2,7),(6,5),(3,4),(4,3),(5,6),(7,2)]
或任何其他有效的配对组,只要它是每对对称的一组,并且该组中的所有项目都包含在一个且仅一个配对中。 A key part of my challenge is to learn to work with monads, specifically Maybe/Just/Nothing, so my current function is Eq a => (a -> a -> Bool) -> [a] -> Maybe [(a,a)]
where Nothing
is returned if a list of tuples including every element cannot be made;我挑战的一个关键部分是学习使用 monad,特别是 Maybe/Just/Nothing,所以我当前的函数是
Eq a => (a -> a -> Bool) -> [a] -> Maybe [(a,a)]
,其中Nothing
如果不能作出元组包括每个元素的列表被返回; for example running (\\x -> \\y -> even(x+y))
on [2,3,4,5,6,7]
would return Nothing
, as you can't pair up all the elements to fit that predicate without leaving some out.例如,在
[2,3,4,5,6,7]
上运行(\\x -> \\y -> even(x+y))
将返回Nothing
,因为您无法配对所有元素以适应它谓词而不遗漏一些。
To start off, I thought I could generate a full list of possible pairs and filter them with the predicate.首先,我想我可以生成一个完整的可能对列表并用谓词过滤它们。 My function at present is
test p xs = filter (uncurry p) [(x,y) | (x:ys) <- tails xs, y <- ys]
我目前的功能是
test p xs = filter (uncurry p) [(x,y) | (x:ys) <- tails xs, y <- ys]
test p xs = filter (uncurry p) [(x,y) | (x:ys) <- tails xs, y <- ys]
, with the idea that later on I can remove tuples with duplicate first values (perhaps somehow using nubBy
?), run swap
from Data.Tuple
on what's left in my list to make my pairs symmetrical, and then run a final check to see if all the elements from the list have been included so I know whether to return nothing. test p xs = filter (uncurry p) [(x,y) | (x:ys) <- tails xs, y <- ys]
的想法,以后我可以删除重复的第一值的元组(可能以某种方式使用nubBy
?),运行swap
从Data.Tuple
在什么在我的左边列表使我的对对称,然后运行最终检查以查看列表中的所有元素是否已包含在内,以便我知道是否不返回任何内容。 I realise, however, that there's probably a better way of going about this that performs fewer redundant actions and does the final check for returning Nothing earlier on.然而,我意识到可能有更好的方法来解决这个问题,即执行更少的冗余操作,并在更早的时候对返回 Nothing 进行最终检查。 I've tried to play around with list comprehension, but I can't come up with anything serviceable.
我试图玩弄列表理解,但我想不出任何有用的东西。
A tuple (x, y)
is inherently ordered: (x, y) != (y, x)
.元组
(x, y)
具有固有的顺序: (x, y) != (y, x)
。 It would be helpful to define an "unordered" pair type for filtering:为过滤定义“无序”对类型会很有帮助:
newtype Pair x = Pair { unpair :: (x, x) }
instance Eq a => Eq (Pair a) where
(Pair p1) == (Pair p2) = p1 == p2 || p1 == swap p2
Then you can use a simpler method of generating sample pairs, using the Applicative
instance for lists.然后您可以使用更简单的方法来生成样本对,使用列表的
Applicative
实例。 You can filter out duplicates later, using Pair
.您可以稍后使用
Pair
过滤掉重复项。
>>> (,) <$> [1, 2, 3] <*> [1, 2, 3]
[(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)]
Once you have filtered the above list, use nub
by first converting all your initial results to Pair
values, deduplicate using nub
, then convert back to tuples:过滤完上述列表后,使用
nub
首先将所有初始结果转换为Pair
值,使用nub
重复数据删除,然后转换回元组:
result :: Eq x => [(x,x)] -> [(x,x)]
result = map unpair . nub . map Pair
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.