0
\$\begingroup\$

I've written a function that produces all combinations of elements in a given list:

createGroups :: [a] -> [[(a, a)]]
createGroups li@(x : xs) = map (\el -> map (\el2 -> (el, el2)) xs) li

These nested maps seem quite messy -- is there a better way to do this?

\$\endgroup\$
3
\$\begingroup\$

It is possible that I'm misunderstanding the problem, but based on your description, I would expect the type of createGroups to be [a] -> [(a, a)] (A flat list, not a list of lists.)

I believe there is bug in your code. Take a look:

> createGroups [1..3]
[[(1,2),(1,3)],[(2,2),(2,3)],[(3,2),(3,3)]]

This result is not what I would expect based on your problem description. Given a list of [1, 2, 3], I would expect the output to be [(1,2),(1,3),(2,3)].

One way to achieve this output is the following:

createGroups :: [a] -> [(a, a)]
createGroups [] = []
createGroups (x:xs) = map ((,) x) xs ++ createGroups xs

> createGroups [1..3]
[(1,2),(1,3),(2,3)

Here is another function that outputs a "flat list" containing the same pairs as your original function, however it's been rewritten to use list comprehension:

createGroups :: [a] -> [(a, a)]
createGroups ls @ (_ : xs) = [(x, pair) | x <- ls, pair <- xs]

> createGroups [1..3]
[(1,2),(1,3),(2,2),(2,3),(3,2),(3,3)]

Lastly, here is a function that produces output identical to yours, rewritten using the monad instance of list:

createGroups :: [a] -> [[(a, a)]]
createGroups li@(x : xs) = do
  first <- li
  return (getPairs first xs)
  where
    getPairs item pairings = do
      pair <- pairings
      return (item, pair)

> createGroups [1..3]
[[(1,2),(1,3)],[(2,2),(2,3)],[(3,2),(3,3)]]

Hopefully this gives you some ideas of different ways to write your function.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.