How can we create a nested keyword list

How can we create a nested keyword list from the following list. The list length can change with time.

list

[:a, :b, :c, :d, :e, :f]

how can we convert it to

[a: [b: [c: [d: [e: [f: [ true ] ]]]]]]

Is it possible with elixir as I tried to use recursion but it’s not working as expected.

Thanks

Yes it is possible. It is even the main purpose of functions in FP

… to take something as input, and transform it to any output.

Please show what You have tried.

1 Like

actually, i have tried this

defp identifier_handling([], key_value), do: key_value

defp identifier_handling([{head, []}], key_value), do: key_value

defp identifier_handling(list, key_value) do
    [key] =
      Keyword.keys(list)
      |> IO.inspect()

    [head | tail] =
      Keyword.values(list)
      |> List.flatten()
      |> IO.inspect()

    identifier_handling([{head, tail}], key_value ++ [{key, head}])
  end

and gives me

[a: :b, b: :c, c: :d, d: :e, e: :f]

which is off course not a nested one

Thanks

When You have an Enumerable, and want to get one value… the usual suspect is Enum.reduce.

iex> l = [:a, :b, :c, :d, :e, :f]
iex> Enum.reduce l, [], fn x, acc -> Keyword.put([], x, acc) end   
# or
iex> Enum.reduce l, [], fn x, acc -> Keyword.new([{x, acc}]) end
[f: [e: [d: [c: [b: [a: []]]]]]]

This code does not solve your problem, but shows how to nest… I would reverse the list first, and add the final true to get it work.

2 Likes

That makes sense now, so whenever one value is related to the other one, I should use Enum.reduce.

How would to put the true in the final list, do I have to loop through the final list and then put the final value?

iex> l |> Enum.reverse() |> Enum.reduce([true], fn x, acc -> Keyword.new([{x, acc}]) end)
[a: [b: [c: [d: [e: [f: [true]]]]]]]

# or the short version...
iex> l |> Enum.reverse() |> Enum.reduce([true], &Keyword.new([{&1, &2}]))
4 Likes

Enum.reduce is extremely powerful and it has reduced the code to just one line.

2 Likes

Here’s my take:

iex> [:a, :b, :c, :d, :e, :f] |> Enum.reverse() |> Enum.reduce([true], &([{&1, &2}]))
[a: [b: [c: [d: [e: [f: [true]]]]]]]
1 Like

Yes, keyword new is not required :slight_smile:

BTW parens are not required too…

iex> [:a, :b, :c, :d, :e, :f] |> Enum.reverse() |> Enum.reduce([true], &[{&1, &2}])
2 Likes

Perhaps a bit :golf: ish, but I’ve never actually used foldr before, so I put this together :grin:

iex(40)> :lists.foldr(&[{&1, &2}], [true], [:a, :b, :c, :d, :e, :f])
[a: [b: [c: [d: [e: [f: [true]]]]]]]
4 Likes

You have List.foldr/3 if you want to make it more Elixirish.

3 Likes

If you want to use recursion, it should be as simple as:

defmodule Solution do
  def run([]), do: [true]
  def run([head | tail]), do: [{head, run(tail)}]
end

Solution.run([:a, :b, :c, :d, :e, :f])
# [a: [b: [c: [d: [e: [f: [true]]]]]]]
2 Likes