简体   繁体   中英

Haskell: Create unique n-tuples from a list of x elements

I have a list of x elements from which I would like to have all possible unique n-tuples.

So I basically am looking for an implementation of

nub . map (take n) . permutations

that doesn't unnecessarily create the duplicates.

For me, this looks like a function that has a good chance of being defined already somewhere.

Is this the case?

Do you mean something like this?

import Data.List (permutations)

choose n list = concatMap permutations $ choose' list [] where
  choose' []     r = if length r == n then [r] else []
  choose' (x:xs) r | length r == n = [r]
                   | otherwise     = choose' xs (x:r) 
                                  ++ choose' xs r

Output:

*Main> choose 2 [0..5]
[[1,0],[0,1],[2,0],[0,2],[3,0],[0,3],[4,0],[0,4],[5,0],[0,5],[2,1]
,[1,2],[3,1],[1,3],[4,1],[1,4],[5,1],[1,5],[3,2],[2,3],[4,2],[2,4]
,[5,2],[2,5],[4,3],[3,4],[5,3],[3,5],[5,4],[4,5]]

Hayoo is very helpful for finding functions. With this query , I found the permutation package, which seems it might do what you want, although I haven't examined the implementation in detail.

But it might be simpler to use one of the solutions discussed here on Stack Overflow. A search turned up some relevant posts. You might look at this discussion of the implementation of the permutations function in Data.List, and modify it to meet your needs.

Since you've asked for tuples, here is a solution exploiting the fact that list is an applicative functor:

Prelude> let list = [0..4]
Prelude> import Control.Applicative
Prelude Control.Applicative> (,) <$> list <*> list
[(0,0),(0,1),(0,2),(0,3),(0,4),(1,0),(1,1),(1,2),...
Prelude Control.Applicative> (,,) <$> list <*> list <*> list
[(0,0,0),(0,0,1),(0,0,2),(0,0,3),(0,0,4),(0,1,0),(0,1,1),...

However, since tuples of different arities are different types by definition, it's impossible to write a universal function which will produce results of different arities based on some n parameter.

Although I must note that this could be solved using some advanced type-level programming techniques by introducing a type-class and instances for type-level naturals representing the arities of tuples you wanted to support, but I'm sure this would be an overkill. Besides, utilizing type-naturals would also be redundant, since all the required information could be determined from the result type, so a simple type class and instances for all tuples you wanted to support would be enough.

You can use Math.Combinatorics.Multiset ( cabal install multiset-comb ), which will avoid duplicates in the output list even if there are duplicates in the input list:

import Math.Combinatorics.Multiset  (fromList, kSubsets, permutations)

permute :: Ord a => Int -> [a] -> [[a]]
permute n = concatMap permutations . kSubsets n . fromList

main = print $ permute 2 [1, 1, 2, 3]

Produces:

[[2,3],[3,2],[1,3],[3,1],[1,2],[2,1],[1,1]]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM