Kevin Etore
Kevin Etore

Reputation: 1124

Elixir lists with tuples modifications

I'm trying to create the following list:

["extract-audio", "audio-format", "mp3"]

Based on:

options = ["extract-audio", "audio-format": "mp3"]

My code to move from the supplied options to the preferred list:

arguments = Enum.map(options, fn(option) ->
      parametrize(option)
    end) |> List.flatten

def parametrize(arg) when is_tuple(arg), do: Tuple.to_list(arg)
def parametrize(arg) when is_binary(arg), do: arg

The returned list is almost correct:

["extract-audio", :"audio-format", "mp3"]

But, I don't quite understand what the semicolon is doing in front of audio-format. And it feels a bit off to create some kind of regex to replace that. Is there perhaps a better solution than my current implementation? I've also thought about maps, but in some cases, I only want an argument and not a key value.

Upvotes: 0

Views: 185

Answers (3)

krishna goteti
krishna goteti

Reputation: 1

There are multiple ways to implement this

1. Recursion

def parameterize(list, acc \\ [])
def parameterize([{k, v} | tail], acc) do
  parameterize(tail, [v, k | acc])
end

def parameterize([element | tail], acc) do
  parameterize(tail, [element | acc])
end

def parameterize([], acc), do: acc |> List.flatten |> Enum.reverse()

2. Using Enum.reduce as answered by Aleksei Matiushkin above

options = ["extract-audio", "audio-format": "mp3"]

options
|> Enum.reduce([], fn            
  {k, v}, acc -> [v, k | acc]
  e, acc -> [e | acc]                   
end)
|> Enum.reverse()

#⇒ ["extract-audio", :"audio-format", "mp3"]

3. Using Enum.flat_map

Enum.flat_map(options, fn
  value when is_tuple(value) -> Tuple.to_list(value)
  any -> [any]
end)

Any of the three can be used based on the comfort :D

Upvotes: 0

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

You don’t need any helper, just use the reducer with multiple clauses. The code below needs one pass through the list and does not require flattening.

options = ["extract-audio", "audio-format": "mp3"]

options
|> Enum.reduce([], fn            
  {k, v}, acc -> [v, k | acc]
  e, acc -> [e | acc]                   
end)
|> Enum.reverse()

#⇒ ["extract-audio", :"audio-format", "mp3"]

You might notice, that :"audio-format" is an atom. That’s because Elixir did some magic building Keyword out of notation "foo": "bar.

["a-b": 42] == [{:"a-b", 42}]
#⇒ true

Upvotes: 3

Ameya Joshi
Ameya Joshi

Reputation: 404

I am not sure if it's efficient way, but this works just

replace

def parametrize(arg) when is_tuple(arg), do: Tuple.to_list(arg)

with

def parametrize(arg) when is_tuple(arg) do
  for el <- Tuple.to_list(arg) do
     if is_atom(el), do: Atom.to_string(el), else: el
  end
end

Upvotes: 0

Related Questions