【问题标题】:How to transform array with duplicates into array with sum of duplicates?如何将具有重复项的数组转换为具有重复项总和的数组?
【发布时间】:2017-01-05 05:54:50
【问题描述】:

所以我已经为此苦苦挣扎了几个小时。我有这个数组[[[4,2]],[[1,2],[1,1]]],我想把这个数组转换成[[[4,2]],[[1,3]]]

所以一个类型为f :: [[[Integer]]] -> [[[Integer]]]的函数

问题

我有一个内部数组长度为 2 的二维数组:[[x,y] .. ] 如果内部数组的头元素重复,则内部数组是重复的:[[1,2],[1,1]] 如果有重复,我想取所有尾部的总和并创建一个新数组,头部作为重复值,重复的总和作为尾部值:[[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]]]`

这是我能做到的最好的。请帮忙!我不知道如何得到想要的结果。

【问题讨论】:

  • 澄清一个细节:如果您的内部列表之一类似于[[1,2],[3,4]],会发生什么?
  • 二维数组没有任何变化。 [[1,2],[3,4]]
  • 类型应该少一个列表,所以f :: [[[Integer]]] -&gt; [[[Integer]]]

标签: list haskell


【解决方案1】:

(初步说明:如果您的最里面的列表总是有两个元素,您应该考虑using pairs instead,如[[(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]]]

如果这是不可接受的,则可以解决这个问题,尽管它可能很烦人和/或需要一些不同的方法。 (除非您不关心“中间层”内部列表中的顺序,否则您可以简单地使用 ifDuplicateGroup = map (groupBy dup . sort) sample,正如 Renezee 在 cmets 中指出的那样。)

【讨论】:

  • 您可以使用sort(或通用sortBy)解决groupBy,例如map (map (foldl1' dedup) . groupBy dup . sort)。在这种情况下,sort 可以正常工作,因为它按元素从头到尾对 [[a]] 进行排序。
  • @Renzeee 确实如此。我考虑过提到这一点,但考虑到问题中使用的措辞,我怀疑“中间层”内部列表中的顺序对 OP 很重要。无论如何,我想将其添加为脚注并没有什么坏处。
【解决方案2】:

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

这是我的临时解决方案。

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) 并使用 fst,snd 而不是 head,tail

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-29
    • 2019-05-21
    • 1970-01-01
    相关资源
    最近更新 更多