如何将带有重复项的数组转换为具有重复项总和的数组?

时间:2017-01-05 05:54:51

标签: list haskell

所以我现在几个小时都在苦苦挣扎。我有这个数组[[[4,2]],[[1,2],[1,1]]],我想将这个数组转换为[[[4,2]],[[1,3]]]

所以类型为f :: [[[Integer]]] -> [[[Integer]]]

的函数

问题

我有一个2d数组,内部数组长度为2:[[x,y] .. ] 如果重复其head元素,则内部数组是重复的:[[1,2],[1,1]] 如果有重复项,我想取所有尾部的总和,并创建一个新的数组,其中head作为重复值,重复项的总和作为尾部值:[[1,2],[1,1]]变为[[[1,3]]

我拥有什么

dup [x,_] [y,_] = x == y

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]]]

ifDuplicateGroup = map (groupBy dup) sample

getSumOfDups n = map sum [concat $ map tail y | y <- n, (length y) > 1]

sumOfSample = map getSumOfDups sample

退货

sumOfSample = [[],[],[],[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]]]`

这是我能做的最好的事情。请帮忙!我无法弄清楚如何获得理想的结果。

2 个答案:

答案 0 :(得分:4)

(初步说明:如果你的最里面的列表总是有两个元素,你应该考虑using pairs instead,就像var CONSTANTS = "https://www.test.com/api/"; var api = CONSTANTS+'api.php?method=register' + '&user_registration='; $http.post(...)... // Same as above 一样。这样就不必处理不可能的情况或担心获取列表了您的函数无法处理的错误长度。也就是说,在下文中我将使用您最初提出的类型。)

虽然您未在[[(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

有一点需要注意:-- 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) 只对相邻的元素进行分组,因此您就有了这样的:

groupBy

如果这是不可接受的,那么解决这个问题是可能的,尽管它可能非常烦人和/或需要一些不同的方法。 (除非你不关心“中间层”内部列表中的顺序,否则你可以简单地使用GHCi> sumOfSample [[[4,2],[4,4]],[[1,2],[2,1],[1,1]]] [[[4,6]],[[1,2],[2,1],[1,1]]] ,正如Renezee在评论中指出的那样。)

答案 1 :(得分:3)

深层列表使代码难以理解。使用类型别名有帮助吗?

这是我的临时解决方案。

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]]    

如果Pair只有2名成员,例如[a,b],您应该使用元组(a,b)并使用fstsnd代替headtail