I enjoy reading Tom Moertel’s blog. In his side bar he lists the Programming Fun Challenge. Here is one of the problems:

Combinations. Create a function combinations that, given a list of strings, returns a list of all the strings that can be formed by picking one character from each of the successive input strings. For example, to compute all of the three-digit binary numbers, you could use combinations as follows:

combinations ( ["01","01","01"] )
=> ["000","001","010","011","100","101","110","111"]

Combinations means something else to me, so I won’t use that terminology. I’ll call my function cprod. I see the proposed problem as the computation of a cross product of lists. Strings are instances of lists in Erlang, so handling lists handles strings too.

The trick is handle a pair of lists, and the special cases: a single list, and any empty lists which might occur. The general case is then handled by recursion.

-module(crossproduct).
-export([cprod/1]).

%% input is a list of lists.
%% most important case: a pair of lists
cp( [[], _] )-> [];

cp( [_, []] )-> [];

cp([A, B]) ->
    [ [X,Y] || X <- A, Y <-B];

%% more than two lists
cp([A, B | Tail]) ->
    cp([cp([A,B]) | Tail]).

%% fewer than two lists
cprod([])-> [];         %% no lists
cprod([[]])-> [];       %% one list, empty

%% one list, non-empty
cprod([A]) ->
    [ [X] || X <- A];

%% the general case, two or more lists
cprod([A|Tail])->
    [lists:flatten(X) || X <- cp([A|Tail])].