Output an element the number of times I want

前端 未结 6 1870
-上瘾入骨i
-上瘾入骨i 2021-01-21 03:11

I have this code:

lado ::  [([Char],Int)] -> [[Char]]
lado xs = [a | (a,b) <- xs]

I need to output this:

> lado [("A         


        
6条回答
  •  耶瑟儿~
    2021-01-21 03:28

    You already use list comprehensions in your attempt. Use them some more.

    lado ::  [([Char],Int)] -> [[Char]]
    lado xs = [a | (a,b) <- xs, b <- [1..b]]
    

    testing:

    > lado [("A",3),("B",2),("C",1)]
    ["A","A","A","B","B","C"]
    

    As your question is saying,

    I have to output "A" 3 times, then "B" 2 times then "C" 1 time

    But if it is really ["A","B","C","A","B","A"] you want, then

    lado ::  [(a,Int)] -> [a]
    lado []        = []
    lado ((a,1):b) = a : lado b
    lado ((a,n):b) = a : lado (b ++ [(a,n-1))])
    

    which can be coded with unfoldr :: (b -> Maybe (a, b)) -> b -> [a] from Data.List,

    lado ::  [(a,Int)] -> [a]
    lado xs = unfoldr g $ xs
      where
      g []        = Nothing
      g ((a,1):b) = Just (a, b)
      g ((a,n):b) = Just (a, b ++ [(a,n-1)])
    

    which can be emulated with Prelude's iterate :: (a -> a) -> a -> [a] etc., as

    lado ::  [(a,Int)] -> [a]
    lado xs = map (fst . head) . takeWhile ( ... ) . iterate g $ xs
      where
      g []            = []
      g ((a, ... ):b) = b
      g ((a,  n  ):b) = b ++ [(a, ... )]
    

    Testing:

    > lado [("A",3),("B",2),("C",1)]
    ["A","B","C","A","B","A"]
    

    Fill in the blanks ... to make it work.


    as @dfeuer notes, the repeated singleton-appending at list's end is detrimental to overall efficiency. With big thanks to his input and discussion, including the two answers and comments here and even a github gist, this can be remedied by the usual FP paradigm (not to say "trick") of building a list in reverse, as

    lado ::  [(a,Int)] -> [a]
    lado xs = go (filter ((> 0) . snd) xs) []
      where
      go []       []  =  []
      go []        r  =  go (reverse r) []
      go ((a,1):b) r  =  a : go b r
      go ((a,n):b) r  =  a : go b ((a,n-1):r)
    

    With the reverse cost amortized over all the output this will add only a constant overhead per each output item.

提交回复
热议问题