Haskell 如果条件为true,则合并多个列表
我一直在想这件事,但似乎我缺乏哈斯克尔的经验无法让我度过难关。我在Stackoverflow上找不到类似的问题(大多数问题都与合并所有子列表有关,没有任何条件) 就这样。假设我有一个这样的列表:Haskell 如果条件为true,则合并多个列表,haskell,Haskell,我一直在想这件事,但似乎我缺乏哈斯克尔的经验无法让我度过难关。我在Stackoverflow上找不到类似的问题(大多数问题都与合并所有子列表有关,没有任何条件) 就这样。假设我有一个这样的列表: [[1, 2, 3], [3, 5, 6], [20, 21, 22]] 如果某种条件为真,是否有一种有效的方法来合并列表?假设我需要合并至少共享一个元素的列表。例如,结果将是: [[1, 2, 3, 3, 5, 6], [20, 21, 22]] 另一个示例(当可以合并所有列表时): 结果是: [
[[1, 2, 3], [3, 5, 6], [20, 21, 22]]
如果某种条件为真,是否有一种有效的方法来合并列表?假设我需要合并至少共享一个元素的列表。例如,结果将是:
[[1, 2, 3, 3, 5, 6], [20, 21, 22]]
另一个示例(当可以合并所有列表时):
结果是:
[[1, 2, 2, 3, 3, 4]]
谢谢你的帮助 关于效率,我不知道该说些什么,但我们可以分解正在发生的事情,至少可以得到几种不同的功能。特定的功能可能是可优化的,但明确需要什么是重要的 让我重新表述这个问题:对于一些集合X,一些二元关系R,和一些二元运算+,产生一个集合Q={X+y | X in X,y in X,xRy}。因此,对于您的示例,我们可能会让X表示一些列表集,R表示“xRy当且仅当X和y中至少有一个元素时”,并且+表示
++
简单的实现可能只是复制集合生成器符号本身
shareElement :: Eq a => [a] -> [a] -> Bool
shareElement xs ys = or [x == y | x <- xs, y <- ys]
v1 :: (a -> a -> Bool) -> (a -> a -> b) -> [a] -> [b]
v1 (?) (<>) xs = [x <> y | x <- xs, y <- xs, x ? y]
最明显的问题是我们得到了四个副本:两个副本来自于列表自身的合并,两个副本来自于列表“双向”的相互合并。出现此问题的原因是List
与Set
不同,因此无法杀死unique。当然,这是一个简单的解决方案,我们将在任何地方使用Set
import Data.Set as Set
v2 :: (a -> a -> Bool) -> (a -> a -> b) -> Set.Set a -> Set.Set b
v2 (?) (<>) = Set.fromList . v1 (?) (<>) . Set.toList
这似乎有效。请注意,我们必须“遍历”List
,因为Set
由于其Ord
约束而不能成为Monad
或Applicative
的实例
我还注意到,Set
中有很多丢失的行为。例如,当我们的关系是对称的时,我们要么丢弃列表中的订单信息,要么必须同时处理xy
和yx
可以编写一些更方便的版本,如
v3 :: Monoid a => (a -> a -> Bool) -> [a] -> [a]
v3 r = v2 r mappend
如果我们假设该关系是一个等式关系,那么就可以建立更有效的关系,从那时起,我们可以在O(n^2)
操作中进行O(nd)
操作,其中d
是该关系的分区(陪集)数
一般来说,这是一个非常有趣的问题。我碰巧在这里写了一些类似的东西: 您可以修改它(尽管我不太确定效率): 输出:
*Main> objects example1
[[20,21,22],[3,5,6,1,2,3]]
*Main> objects example2
[[3,4,2,3,1,2]]
“可以合并任何两个列表,还是只合并连续的列表?”哈马尔忘了提到这一点。任意两个列表。一个猜测:这听起来像是实现了某种不相交的联合数据结构。列表并不是表示这一点的好方法。你能确切地告诉我们你想在这里实现什么吗?@NiklasB提供的例子和我想做的差不多——没有特别的用途。我一定要做一些关于不相交并的研究。因此,我想没有半途而废的方法来处理列表?如果你一定要处理列表,一般的方法是使用第一个列表,在每个列表中添加一个公共元素并重复,直到不再添加列表为止(因为你可以使用
[[1,2]、[3,4]、[1,4]]
,其中第一次通过不会拾取所有内容)。在未与第一个连接的子列表上递归。但我会寻找更好的数据结构。。。
Prelude Set> p $ Set.fromList $ map Set.fromList [[1,2], [2,1]]
fromList [fromList [1,2]]
v3 :: Monoid a => (a -> a -> Bool) -> [a] -> [a]
v3 r = v2 r mappend
import Data.List (delete, intersect)
example1 = [[1, 2, 3], [3, 5, 6], [20, 21, 22]]
example2 = [[1, 2], [2, 3], [3, 4]]
objects zs = map concat . solve zs $ [] where
areConnected x y = not . null . intersect x $ y
solve [] result = result
solve (x:xs) result =
let result' = solve' xs [x]
in solve (foldr delete xs result') (result':result) where
solve' xs result =
let ys = filter (\y -> any (areConnected y) result) xs
in if null ys
then result
else solve' (foldr delete xs ys) (ys ++ result)
*Main> objects example1
[[20,21,22],[3,5,6,1,2,3]]
*Main> objects example2
[[3,4,2,3,1,2]]