1

I have a given list, e.g. [2, 3, 5, 587] and I want to have a complete list of the combination. So want something like [2, 2*3,2*5, 2*587, 3, 3*5, 3*587, 5, 5*587, 587]. Since I am on beginner level with Haskell I am curious how a list manipulation would look like.

Additionally I am curious if the computation of the base list might be expensive how would this influence the costs of the function? (If I would assume the list has limit values, i.e < 20)

Rem.: The order of the list could be done afterwards, but I have really no clue if this is cheaper within the function or afterwards.

LeO
  • 4,238
  • 4
  • 48
  • 88
  • 1
    Permutations would mean all the list elements but shuffled in different orders. Are you sure you don't mean "combinations"? Also, why are you getting only groups of 1 or two elements and not groups of 3 or 4? – hugomg Jan 28 '14 at 20:34
  • Yeah, you are right, no permutation, more a combination. You are also right, that the groups of 3 combination is of interest, although not mentioned explicitly. But I guess, depending on the suggestions this should be a minor step to adapt it finally. Anyway, your questions/doubts gave me a little re-think of 'What do I wanna achieve?'. Thx. – LeO Jan 29 '14 at 07:36
  • [This SO question](http://stackoverflow.com/questions/21265454/subsequences-of-length-n-from-list-performance/21268310) contains a good discussion on generating combinations in Haskell. – ErikR Jan 29 '14 at 07:46

3 Answers3

6

The others have explained how to make pairs, so I concern myself here with getting the combinations.

If you want the combinations of all lengths, that's just the power set of your list, and can be computed the following way:

powerset :: [a] -> [[a]]
powerset (x:xs) = let xs' = powerset xs in xs' ++ map (x:) xs'
powerset []     = [[]]

-- powerset [1, 2] === [[],[2],[1],[1,2]]
-- you can take the products:
-- map product $ powerset [1, 2] == [1, 2, 1, 2]

There's an alternative powerset implementation in Haskell that's considered sort of a classic:

import Control.Monad

powerset = filterM (const [True, False])

You could look at the source of filterM to see how it works essentially the same way as the other powerset above.

On the other hand, if you'd like to have all the combinations of a certain size, you could do the following:

combsOf :: Int -> [a] -> [[a]]
combsOf n _ | n < 1 = [[]]
combsOf n (x:xs)    = combsOf n xs ++ map (x:) (combsOf (n - 1) xs)
combsOf _ _         = []

-- combsOf 2 [1, 2, 3] === [[2,3],[1,3],[1,2]]
András Kovács
  • 29,931
  • 3
  • 53
  • 99
  • +1. the last one also reminiscent of SICP's "make-change". :) --- a related problem, though it wasn't asked: if repetitions are allowed in (ordered) input, produce all unique combinations. – Will Ness Jan 29 '14 at 10:26
  • @WillNess: I also recall the coin change problem fondly; [here's](https://gist.github.com/AndrasKovacs/8686121) a pretty and fast solution that I worked out quite a while ago, if you're interested:) – András Kovács Jan 29 '14 at 11:32
2

So it seems what you want is all pairs of products from the list:

ghci> :m +Data.List
ghci> [ a * b | a:bs <- tails [2, 3, 5, 587], b <- bs ]
[6,10,1174,15,1761,2935]

But you also want the inital numbers:

ghci> [ a * b | a:bs <- tails [2, 3, 5, 587], b <- 1:bs ]
[2,6,10,1174,3,15,1761,5,2935,587]

This uses a list comprehension, but this could also be done with regular list operations:

ghci> concatMap (\a:bs -> a : map (a*) bs) . init $ tails [2, 3, 5, 587]
[2,6,10,1174,3,15,1761,5,2935,587]

The latter is a little easier to explain:

  • Data.List.tails produces all the suffixes of a list:

    ghci> tails [2, 3, 5, 587]
    [[2,3,5,587],[3,5,587],[5,587],[587],[]]
    
  • Prelude.init drops the last element from a list. Here I use it to drop the empty suffix, since processing that causes an error in the next step.

    ghci> init [[2,3,5,587],[3,5,587],[5,587],[587],[]]
    [[2,3,5,587],[3,5,587],[5,587],[587]]
    
    ghci> init $ tails [2, 3, 5, 587]
    [[2,3,5,587],[3,5,587],[5,587],[587]]
    
  • Prelude.concatMap runs a function over each element of a list, and combines the results into a flattened list. So

    ghci> concatMap (\a -> replicate a a) [1,2,3]
    [1, 2, 2, 3, 3, 3]
    
  • \(a:bs) -> a : map (a*) bs does a couple things.

    1. I pattern match on my argument, asserting that it matches an list with at least one element (which is why I dropped the empty list with init) and stuffs the initial element into a and the later elements into bs.
    2. This produces a list that has the same first element as the argument a:, but
    3. Multiplies each of the later elements by a (map (a*) bs).
rampion
  • 87,131
  • 49
  • 199
  • 315
  • the OP later clarified in the comments that they want all the combinations, not just pairs. This is probably intended to produce all the divisors of a number from its prime factorization. :) – Will Ness Jan 29 '14 at 09:55
  • right about the intention - good guess, but the given approach is wrong ;) e.g. 2*2*587 wouldn't lead to the divisor 4 (!) But the given solution is fine for list manipulation - which was one of my objective to see how it might work. – LeO Jan 29 '14 at 10:05
1

You can get the suffixes of a list using Data.List.tails. This gives you a list of lists, you can then do the inner multiplications you want on this list with a function like:

prodAll [] = []
prodAll (h:t) = h:(map (* h) $ t)

You can then map this function over each inner list and concatenate the results:

f :: Num a => [a] -> [a]
f = concat . map prodAll . tails
Lee
  • 142,018
  • 20
  • 234
  • 287