Performance 创建集合中所有元素对的数据集的最有效方法?
给定一个包含任意数量任意类型元素的任意集合,例如Performance 创建集合中所有元素对的数据集的最有效方法?,performance,haskell,Performance,Haskell,给定一个包含任意数量任意类型元素的任意集合,例如 mySet1 = Set.fromList [1,2,3,4] 或 或 对于某些数据构造函数A、B、C、D 生成所有无序元素对集合的计算效率最高的方法是给定集合?即 setPairs mySet1 == Set.fromList [(1,2),(1,3),(1,4),(2,3),(2,4),(3,4)] 或 或 我最初天真的猜测是: setPairs s = fst $ Set.fold (\e (pairAcc, elements
mySet1 = Set.fromList [1,2,3,4]
或
或
对于某些数据构造函数A、B、C、D
生成所有无序元素对集合的计算效率最高的方法是给定集合?即
setPairs mySet1 == Set.fromList [(1,2),(1,3),(1,4),(2,3),(2,4),(3,4)]
或
或
我最初天真的猜测是:
setPairs s = fst $ Set.fold
(\e (pairAcc, elementsLeft) ->
( Set.fold
(\e2 pairAcc2 ->
Set.insert (e2, e) pairAcc2
) pairAcc $ Set.delete e elementsLeft
, Set.delete e elementsLeft )
) (Set.empty, s) s
但这肯定不是最好的解决方案吗?首先,您需要生成所有集合<来自控件的代码>复制项。Monad帮助完成此操作
λ> replicateM 2 [1..4]
[[1,1],[1,2],[1,3],[1,4],[2,1],[2,2],[2,3],[2,4],[3,1],[3,2],[3,3],[3,4],[4,1],[4,2],[4,3],[4,4]]
然后需要过滤对,其中第二个元素大于第一个元素
λ> filter (\[x,y] -> x < y) $ replicateM 2 [1 .. 4]
[[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
所以,如果我答对了你的问题,你可以使用pairs mySet
,其中pairs生成mySet
的所有无序对的列表
这是你想要的吗
UPD:
可以使用更清晰、更快速的技术来创建这样的子列表,因此这里是另一个对的实例:
import Data.Set
import Control.Monad
import Data.List
mySet = Data.Set.fromList [1,2,3,4]
--setOfPairs = Data.Set.fromList [(1,2),(1,3),(1,4),(2,3),(2,4),(3,4)]
setOfPairs = Data.Set.fromList $ pairs mySet
pairs :: Ord a => Set a -> [(a,a)]
pairs x = Data.List.map (\[x,y] -> (x,y)) $ Data.List.filter (\[x,y] -> x < y) $ replicateM 2 $ toList x
pairs :: Ord a => Set a -> [(a,a)]
pairs set = [(x,y) | let list = toList set, x <- list, y <- list, x < y]
pairs::Ord a=>设置a->[(a,a)]
pairs set=[(x,y)| let list=toList set,x因此,这里是第一次尝试使用列表来回转换的解决方案。同样,我不确定这是实现这一点的最快方法,但我知道,在集合上进行迭代并不是非常有效
import Data.List
import qualified Data.Set as S
pairs :: S.Set String -> S.Set (String,String)
pairs s = S.fromList $ foldl' (\st e -> (zip l e) ++ st) [] ls
where (l:ls) = tails $ S.toList s
通过将拉链折叠到尾巴上,您可以获得一种很好且有效的方法来创建无序对集。然而,本能鼓励我,可能会有一种更优雅的单体过滤器或折叠解决方案。我会继续思考
[编辑]
因此,这里是一个不需要收费表的更快的解决方案(但不是因为功率集的大小)
import Data.List
import qualified Data.Set as S
import qualified Data.Foldable as F
pairs :: (Ord a) => S.Set a -> S.Set (a,a)
pairs s = S.fromList $ foldl two [] $ F.foldlM (\st e -> [[e]++st,st]) [] s
where two st (x:xa:[]) = (x,xa) : st
two st _ = st
在一元列表上使用幂集解决方案来构建幂集,然后过滤掉幂集对。如有必要,我可以更详细地介绍。基准测试可能会证明我错了,但我的怀疑是,保持在集表示中是没有好处的。您将需要O(n^2)不管怎样,因为这是输出的大小。关键的优势是生成列表,这样您就可以使用对s.fromDistinctAscList
的调用,这样构建集合本身只需花费O(n)
以下内容非常简洁,保留了相当多的共享,通常是我能想象到的最简单、最直接和直观的解决方案
pairs s = S.fromDistinctAscList . concat $ zipWith zip (map (cycle . take 1) ts) (drop 1 ts)
where ts = tails $ S.toList s
编辑
更短/更清晰(不确定性能,但可能同样好/更好):
对s=s.fromDistinctAscList[(x,y)|(x:xt)考虑这一点最简单的方法是列表理解,答案几乎是自己写的……是的,我可以看到这是用集合完成的,但它可能不会像filterM或列表理解解决方案那样优雅。转换为列表是一种选项,还是列表航路点使解决方案对您不可行?@Erik Hinton:如果列表提供了最快的方法,那么转换到列表就可以了。感谢您提供的详细答案。不幸的是,这对字符串集不起作用,因为它们不在Ord中。请给出一些示例,说明您对setOfPairs
的期望值。对不起,当然字符串和Ord中的任何数据类型的元素一样在Ord中一套。我很抱歉。但是转换到列表真的是最快的方法吗?我只是一个初学者,没有比较一些算法和数据类型的经验。我所能说的是-转换到列表是解决您的问题的最简单的方法。我的本能是同意您的看法。唯一关心的是是否有一些伟大的问题toList
中的开销。但是,我怀疑它是否会非常昂贵。toList
被定义为折叠,这是直接定义的。我想这个解决方案比其他解决方案使用更少的中间内存,因为它尽可能地流式处理。最后一组使用的内存当然是going无论如何都要花费相同的成本。我做了一些基准测试。上面给出的两种解决方案都是迄今为止给出的解决方案中最快的。使用列表理解的较短版本对于大集合更快,但对于小集合则更慢。谢谢!在快速基准测试中,使用toList的解决方案比不使用toList的解决方案快得多。Since功率集的大小随给定集的大小呈指数增长,此解决方案的时间消耗也是如此。干杯,啊,非常好。当有疑问时,请始终相信基准。干杯,
import Data.Set
import Control.Monad
import Data.List
mySet = Data.Set.fromList [1,2,3,4]
--setOfPairs = Data.Set.fromList [(1,2),(1,3),(1,4),(2,3),(2,4),(3,4)]
setOfPairs = Data.Set.fromList $ pairs mySet
pairs :: Ord a => Set a -> [(a,a)]
pairs x = Data.List.map (\[x,y] -> (x,y)) $ Data.List.filter (\[x,y] -> x < y) $ replicateM 2 $ toList x
pairs :: Ord a => Set a -> [(a,a)]
pairs set = [(x,y) | let list = toList set, x <- list, y <- list, x < y]
import Data.List
import qualified Data.Set as S
pairs :: S.Set String -> S.Set (String,String)
pairs s = S.fromList $ foldl' (\st e -> (zip l e) ++ st) [] ls
where (l:ls) = tails $ S.toList s
import Data.List
import qualified Data.Set as S
import qualified Data.Foldable as F
pairs :: (Ord a) => S.Set a -> S.Set (a,a)
pairs s = S.fromList $ foldl two [] $ F.foldlM (\st e -> [[e]++st,st]) [] s
where two st (x:xa:[]) = (x,xa) : st
two st _ = st
pairs s = S.fromDistinctAscList . concat $ zipWith zip (map (cycle . take 1) ts) (drop 1 ts)
where ts = tails $ S.toList s
pairs s = S.fromDistinctAscList [(x,y) | (x:xt) <- tails (S.toList s), y <- xt]