# Forming a 3D cube from elements in a list

I have a list say [A, B, C,D,E,F,G,H]

I wish to form a 3D cube-like structure using these elements where neighbors of each element will be stored in a tuple.
I want the approach through coordinates.
Each element should be given x, y and z coordinates and based on x,y,z I will fetch the neighbors.

My problem is if I use a nested for loop then assignment within loop is not happening which is not allowing me to iterate through the list.

``````index = -1

for x <- 1..row_length do
for y <- 1..row_length do
for z <- 1..row_length do
Index = index + 1
{Enum.at(list,index), x, y, z}
end
end
end
``````

I tried using

``````g = Enum.map(a, fn node ->
for x <- 1..2 do
for y <- 1..2 do
for z <- 1..2 do
index = index + 1
{node, index, x, y, z}
end
end
end
end)
``````

But the above code two code snippets give me
[
[
[[{A, 1, 1, 1}, {A, 1, 1, 2}], [{A, 1, 2, 1}, {A, 1, 2, 2}]],
[[{A, 2, 1, 1}, {A, 2, 1, 2}], [{A, 2, 2, 1}, {A, 2, 2, 2}]]
],
[
[[{B, 1, 1, 1}, {B, 1, 1, 2}], [{B, 1, 2, 1}, {B, 1, 2, 2}]],
[[{B, 2, 1, 1}, {B, 2, 1, 2}], [{B, 2, 2, 1}, {B, 2, 2, 2}]]
],
[
[[{C, 1, 1, 1}, {C, 1, 1, 2}], [{C, 1, 2, 1}, {C, 1, 2, 2}]],
[[{C, 2, 1, 1}, {C, 2, 1, 2}], [{C, 2, 2, 1}, {C, 2, 2, 2}]]
],
[
[[{D, 1, 1, 1}, {D, 1, 1, 2}], [{D, 1, 2, 1}, {D, 1, 2, 2}]],
[[{D, 2, 1, 1}, {D, 2, 1, 2}], [{D, 2, 2, 1}, {D, 2, 2, 2}]]
],
[
[[{E, 1, 1, 1}, {E, 1, 1, 2}], [{E, 1, 2, 1}, {E, 1, 2, 2}]],
[[{E, 2, 1, 1}, {E, 2, 1, 2}], [{E, 2, 2, 1}, {E, 2, 2, 2}]]
],
[
[[{F, 1, 1, 1}, {F, 1, 1, 2}], [{F, 1, 2, 1}, {F, 1, 2, 2}]],
[[{F, 2, 1, 1}, {F, 2, 1, 2}], [{F, 2, 2, 1}, {F, 2, 2, 2}]]
],
[
[[{G, 1, 1, 1}, {G, 1, 1, 2}], [{G, 1, 2, 1}, {G, 1, 2, 2}]],
[[{G, 2, 1, 1}, {G, 2, 1, 2}], [{G, 2, 2, 1}, {G, 2, 2, 2}]]
],
[
[[{H, 1, 1, 1}, {H, 1, 1, 2}], [{H, 1, 2, 1}, {H, 1, 2, 2}]],
[[{H, 2, 1, 1}, {H, 2, 1, 2}], [{H, 2, 2, 1}, {H, 2, 2, 2}]]
]
]

Where as desired results would be
{A, 1,1,1}
{B,1,1,2}
{C,1,2,1}
{D,1,2,2}
{E,2,1,1}
{F,2,1,2}
{G,2,2,1}
{H,2,2,2}

Hi @rishabhrrk it looks like youâ€™re new here, so first of all let me say â€śwelcome!â€ť

I see at least 3 misunderstandings in your question, so Iâ€™m guessing you are new to Elixir, and possibly functional programming too. They are not for loops, but list comprehensions. They are much more powerful. You can get a cartesian product of values with a single use of `for` by using multiple generators. You cannot mutate variables, especially ones outside of the scope. Your approach to updating `index` is trying to do that. Also, upper case names in Elixir are intended to be used for module names, not for variable names.

Hereâ€™s how Iâ€™d approach the situation. First you want the cartesian product of a range of 1â€¦row_index in 3 variables, so:

``````iex> row_length = 2
2
iex> coords = for x <- 1..row_length, y <- 1..row_length, z <- 1..row_length, do: {x,y,z}
[
{1, 1, 1},
{1, 1, 2},
{1, 2, 1},
{1, 2, 2},
{2, 1, 1},
{2, 1, 2},
{2, 2, 1},
{2, 2, 2}
]
``````

But you want to prefix each tuple with an element from your list of node names. Iâ€™ll name the nodes with lower case atoms as is more idiomatic Elixir. And Iâ€™ll use `Enum.zip` to get a pairwise tuple from both the nodes and `coords`

``````iex> nodes = [:a, :b, :c, :d, :e, :f, :g, :h]
[:a, :b, :c, :d, :e, :f, :g, :h]
iex> zipped = Enum.zip(nodes, coords)
[
a: {1, 1, 1},
b: {1, 1, 2},
c: {1, 2, 1},
d: {1, 2, 2},
e: {2, 1, 1},
f: {2, 1, 2},
g: {2, 2, 1},
h: {2, 2, 2}
]
``````

Thereâ€™s a little bit of a display artifact there because Elixir thinks you have a keyword list. Each row is really a tuple within a tuple, for example `{:a, {1, 1, 1}}`. We can then use `Enum.map` to get you a flat tuple like you desire:

``````iex> Enum.map(zipped, fn {i, {j, k, l}} -> {i, j, k, l} end)
[
{:a, 1, 1, 1},
{:b, 1, 1, 2},
{:c, 1, 2, 1},
{:d, 1, 2, 2},
{:e, 2, 1, 1},
{:f, 2, 1, 2},
{:g, 2, 2, 1},
{:h, 2, 2, 2}
]
``````

This could also be done with a bit of syntactic sugar and a pipeline all at once without intermediate variables like this:

`````` ~w(a b c d e f g h)a
|> Enum.zip(for x <- 1..row_length, y <- 1..row_length, z <- 1..row_length, do: {x, y, z})
|> Enum.map(fn {i, {j, k, l}} -> {i, j, k, l} end)
``````
6 Likes

Thanks for the warm welcome. All your correct.
Thanks, the solution helped.

I couldnâ€™t help but tweak this a bit more. Itâ€™s a fun little problem. Iâ€™m sure for an 8 element list the performance implications probably fall within the range of noise, but I wanted to see if I could do this with only one iteration of the values, plus I havenâ€™t really spent time playing with the new `reduce` option of list comprehensions yet. Hereâ€™s basically the one-liner I came up with (if youâ€™ll forgive the assignment to `row_length`).

``````iex> row_length = 2
2
iex> (for x <- row_length..1, y <- row_length..1, z <- row_length..1, reduce: {~w(h g f e d c b a)a, []}, do: ({[n | names], coords} -> {names, [{n, x, y, z} | coords]})) |> elem(1)
[
{:a, 1, 1, 1},
{:b, 1, 1, 2},
{:c, 1, 2, 1},
{:d, 1, 2, 2},
{:e, 2, 1, 1},
{:f, 2, 1, 2},
{:g, 2, 2, 1},
{:h, 2, 2, 2}
]
``````

In this, I create a 2-tuple initial accumulator containing the node names I have not used yet and the coordinates to output (empty list to begin with). In each iteration of the comprehension I destructure the accumulator, popping off the next unused node name, and I set the new accumulator as the remaining node names and the new coordinate prepended to the prior list. Finally, after the comprehension finishes, I pull the desired results from tuple element 1. And I do it all starting in reverse order so after all the prepending I end up with the desired order and avoid a final reverse.

Iâ€™m not sure if I should be proud of ashamed of coming up with this It does demonstrate how versatile list comprehensions are though.

2 Likes