Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elixir how to emulate nested comprehensions

Tags:

elixir

def letterCombinations(text) do
  dict = %{"2" => ["a","b","c"], "3" => ["d","e","f"], "4" => ["g","h","i"], "5" => ["j","k","l"], "6" => ["m","n","o"], "7" => ["p","q","r"], "8" => ["s","t","u"],"9" => "vwx"}
  numbers = String.codepoints(text)
  test1 = dict["2"]
  test2 = dict["3"]
  test3 = dict["4"]
  for tst1 <- test1, tst2 <- test2,tst3 <- test3 do
    "#{tst1}#{tst2}#{tst3}"
  end

 end

Imagine an old cell phone, the buttons had a set of 3 letters. I want to make a function that would return all the possible combinations of letters.(The letters are assigned starting from the number 2) Example

letterCombination("23")

would return

 ["ad" ,"ae" ,"af" ,"bd" ,"be" ,"bf" ,"cd" ,"ce" ,"cf"]

The input was "23", therefore I expect the output to be all the messages of length 2 that you could have got by selecting one of the available letters for each number in that order. In the function above you can see the mappings and the idea of what I try to accomplish. The problem is that I don't know how to do it without nested comprehensions.

like image 281
IOEnthusiast Avatar asked May 26 '26 19:05

IOEnthusiast


1 Answers

If you know the input is only two characters, you can use the <<>> bitstring operator to match the two values, and then it becomes a simple comprehension with two generators:

def letterCombination(<<key1::binary-1, key2::binary-1>>) do
  for l1 <- @keypad[key1], l2 <- @keypad[key2], do: l1 <> l2
end

If you want to be more general and accept any length of input, then as Silvio Mayolo pointed out a single comprehension is not enough, you need to use recursion. This is mostly a simplified example of Silvio's answer, adjusted to take advantage of the bitstring operator in the function header.

def letterCombination(""), do: [""]

def letterCombination(<<key::binary-1, rest::binary>>) do
  for letter <- @keypad[key], tail <- letterCombination(rest), do: letter <> tail
end

Usage:

iex(1)> Example.letterCombination("234")
["adg", "adh", "adi", "aeg", "aeh", "aei", "afg", "afh", "afi", "bdg", "bdh",
 "bdi", "beg", "beh", "bei", "bfg", "bfh", "bfi", "cdg", "cdh", "cdi", "ceg",
 "ceh", "cei", "cfg", "cfh", "cfi"]

Note I defined the keypad in a module attribute like this:

@keypad %{ "2" => ["a", "b", "c"],  "3" => ["d", "e", "f"], ... }
like image 148
Adam Millerchip Avatar answered Jun 03 '26 13:06

Adam Millerchip



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!