List 如何将具有重复项的数组转换为具有重复项之和的数组?
所以我已经为此挣扎了几个小时了。我有这个数组List 如何将具有重复项的数组转换为具有重复项之和的数组?,list,haskell,List,Haskell,所以我已经为此挣扎了几个小时了。我有这个数组[[4,2]],[[1,2],[1,1]]],我想把这个数组转换成[[4,2]],[[1,3]] 因此,类型为f::[[[Integer]]->[[[Integer]]]] 问题 我有一个内部数组长度为2的2d数组:[[x,y]..] 如果内部数组的头元素重复,则该数组是重复的:[[1,2],[1,1]] 如果有重复项,我想取所有尾部的总和,创建一个新数组,头部作为重复值,重复项的总和作为尾部值:[[1,2],[1,1]变成[[1,3]] 我所拥有的
[[4,2]],[[1,2],[1,1]]]
,我想把这个数组转换成[[4,2]],[[1,3]]
因此,类型为f::[[[Integer]]->[[[Integer]]]]
问题
我有一个内部数组长度为2的2d数组:[[x,y]..]
如果内部数组的头元素重复,则该数组是重复的:[[1,2],[1,1]]
如果有重复项,我想取所有尾部的总和,创建一个新数组,头部作为重复值,重复项的总和作为尾部值:[[1,2],[1,1]
变成[[1,3]]
我所拥有的
所需结果:
sumOfSample =
[[[3,5],[2,3],[1,1]],
[[3,5],[2,3],[4,2],[1,2]],
[[3,5],[2,3],[4,2],[1,2]],
[[4,2],[1,3]]]`
这是我所能做的最好的。请帮助我!我不知道如何得到期望的结果。
(初步注释:如果你的最内层列表总是有两个元素,你应该考虑,如<代码> [[(4],2)],[ [(1,2),(1,1)] ]。这样就不必处理不可能的情况,也不必担心函数无法处理长度错误的列表。也就是说,下面我将使用您最初提出的类型。)
虽然您没有在sumOfSample
中使用它,但您使用ifDuplicateGroup
的方法是正确的:
-- I have specialised the functions to Integer; they could be more general.
-- Also note that dup is partial; it only works with lists of two elements.
-- That is the sort of issue you might avoid by using pairs.
dup :: [Integer] -> [Integer] -> Bool
dup [x,_] [y,_] = x == y
-- Making it a function by not supplying 'sample'.
ifDuplicateGroup :: [[[Integer]]] -> [[[[Integer]]]]
ifDuplicateGroup = map (groupBy dup)
ifDuplicateGroup
将为您提供一个四层嵌套列表——一个由分组的两个元素列表组成的列表。下一步是通过挤压组,从而删除重复项,将其变回三层嵌套列表。这可以通过折叠完成,通过两层映射应用(以便折叠的列表是最里面的列表组):
需要注意的一点是,groupBy
仅对相邻元素进行分组,因此您有:
GHCi> sumOfSample [[[4,2],[4,4]],[[1,2],[2,1],[1,1]]]
[[[4,6]],[[1,2],[2,1],[1,1]]]
如果这是不可接受的,那么解决这一问题是可能的,尽管这可能非常烦人,并且/或者需要一种不同的方法(除非您不关心“中间层”内部列表中的顺序,否则您可以简单地使用
ifDuplicateGroup=map(groupBy dup.sort)sample
,正如Renezee在评论中指出的那样)深度列表使代码难以理解。使用类型别名是否有帮助
这是我的临时解决方案
import Data.List
type Pair = [Int]
type PairList = [Pair]
sample :: [PairList]
sample = [[[3,5],[2,3],[1,1]],
[[3,5],[2,3],[4,2],[1,2]],
[[3,5],[2,3],[4,2],[1,2]],
[[4,2],[1,2],[1,1]]]
dupList :: PairList -> PairList
dupList xs = ss
where gs = groupBy dup xs
ss = map sumGroup gs
sumGroup :: PairList -> Pair
sumGroup xs = [h,t]
where h = head $ head xs
t = sum $ concatMap tail xs
dup :: Pair -> Pair -> Bool
dup xs ys = head xs == head ys
main :: IO ()
main = do
putStrLn "input"
mapM_ print sample
putStrLn "output"
let output = map dupList sample
mapM_ print output
耶尔德
如果
Pair
只有两个成员,例如[a,b]
,你应该使用tuple(a,b)
并使用fst
,snd
而不是head
,tail
,来澄清一个细节:如果你的内部列表中有一个类似于[1,2],[3,4]的内容,该怎么办
?2d数组没有任何内容保持不变。[[1,2],[3,4]]
类型应该少一个列表深度,因此f:[[[Integer]]]->[[[Integer]]]]]
。您可以使用sort
(或通用的sortBy
)解决map(map(foldl1'dedup.).groupBy dup.sort)之类的问题
。在这种情况下,sort
可以很好地工作,因为它对元素从头到尾进行排序。@Renzeee确实如此。我考虑过提到这一点,但考虑到问题中使用的措辞,我怀疑“中间层”内部列表的顺序对OP很重要。无论如何,我想作为脚注添加这一点并没有什么坏处。
-- Combining function for the fold. Note that, just like dup, it is partial.
dedup :: [Integer] -> [Integer] -> [Integer]
dedup [x, acc] [_, y] = [x, acc + y]
-- foldl1' doesn't work with empty lists. That is not a problem here, given
-- that group does not produce empty (inner) lists.
sumOfSample :: [[[[Integer]]]] -> [[[Integer]]]
sumOfSample = map (map (foldl1' dedup)) . ifDuplicateGroup
-- Or, equivalently:
-- sumOfSample = map (map (foldl1' dedup) . groupBy dup)
GHCi> sumOfSample [[[4,2],[4,4]],[[1,2],[2,1],[1,1]]]
[[[4,6]],[[1,2],[2,1],[1,1]]]
import Data.List
type Pair = [Int]
type PairList = [Pair]
sample :: [PairList]
sample = [[[3,5],[2,3],[1,1]],
[[3,5],[2,3],[4,2],[1,2]],
[[3,5],[2,3],[4,2],[1,2]],
[[4,2],[1,2],[1,1]]]
dupList :: PairList -> PairList
dupList xs = ss
where gs = groupBy dup xs
ss = map sumGroup gs
sumGroup :: PairList -> Pair
sumGroup xs = [h,t]
where h = head $ head xs
t = sum $ concatMap tail xs
dup :: Pair -> Pair -> Bool
dup xs ys = head xs == head ys
main :: IO ()
main = do
putStrLn "input"
mapM_ print sample
putStrLn "output"
let output = map dupList sample
mapM_ print output
>runhaskell listlist.hs
input
[[3,5],[2,3],[1,1]]
[[3,5],[2,3],[4,2],[1,2]]
[[3,5],[2,3],[4,2],[1,2]]
[[4,2],[1,2],[1,1]]
output
[[3,5],[2,3],[1,1]]
[[3,5],[2,3],[4,2],[1,2]]
[[3,5],[2,3],[4,2],[1,2]]
[[4,2],[1,3]]