# Elementwise join

I have two tensors of arbitrary but equal rank n (and equal dimensions): A and B, and I want to get a third tensor of rank n + 1, C.

I want to do a element by element Join, so the element in A and the corresponding element in B are contracted into a list in C.

For example, with n = 2:

A = {{a[0,0],a[1,0]},{a[0,1],a[1,1]}};
B = {{b[0,0],b[1,0]},{b[0,1],b[1,1]}};


then:

C = {{ {a[0,0],b[0,0]} , {a[1,0],b[1,0]} },{ {a[0,1],b[0,1]} , {a[1,1],b[1,1]} }}


I think it might be doable with some combination of Inner and List, but I'm not sure.

• Note: C is a built-in symbol in System  and it's not wise to assign/modify it unless absolutely necessary.
– rm -rf
Commented Jan 7, 2013 at 23:19
• Sorry, I was using A, B and C as example variables. Commented Jan 7, 2013 at 23:20
• This is very strongly related, although the way the two questions are worded, they're entirely different mathematica.stackexchange.com/q/17291/5
– rm -rf
Commented Jan 7, 2013 at 23:35
• Related: (6102), (9012) Commented Jun 13, 2020 at 13:40

## 5 Answers

Here are a couple of possibilities.

MapThread[Riffle[{#1}, {#2}] &, {aA, bB}, 2]

(* Out[64]= {{{a[0, 0], b[0, 0]}, {a[1, 0], b[1, 0]}}, {{a[0, 1],
b[0, 1]}, {a[1, 1], b[1, 1]}}} *)

Transpose[ArrayFlatten[{aA, bB}], {3, 1, 2}]

(* Out[72]= {{{a[0, 0], b[0, 0]}, {a[1, 0], b[1, 0]}}, {{a[0, 1],
b[0, 1]}, {a[1, 1], b[1, 1]}}} *)


Another that I like less:

Map[Thread, Thread[{aA, bB}]]


--- edit ---

Actually that second one should just be

Transpose[{aA, bB}, {3, 1, 2}]


The ArrayFlatten was not needed in this case (it can be useful somethimes though). And in case it was not clear, the lists are:

aA = {{a[0, 0], a[1, 0]}, {a[0, 1], a[1, 1]}};
bB = {{b[0, 0], b[1, 0]}, {b[0, 1], b[1, 1]}};


--- end edit ---

Here's a fairly simple way of doing it (ignore the front end's syntax warning):

Function[, {##}, Listable][A, B]
(* {{{a[0, 0], b[0, 0]}, {a[1, 0], b[1, 0]}},
{{a[0, 1],  b[0, 1]}, {a[1, 1], b[1, 1]}}} *)

• Why does that work? It is very interesting, but what if I want to make a[0,0] a list as well? Commented Jan 7, 2013 at 23:48
• If you consider element-wise multiplication A B, that is possible because of the Listable attribute of Times. In other words, it threads over lists in its arguments. What I've done above is similar – it creates a pure function that "joins" the arguments ({#}) and threads it over lists (Listable). The omitted argument is taken as Null. I don't understand what you mean by wanting to make a[0,0] a list as well, as it's no longer element-wise join, as you wanted.
– rm -rf
Commented Jan 7, 2013 at 23:55
• +1. You are too fast, I am running out of tricks :-) Commented Jan 8, 2013 at 0:01

Maybe a pedagogical alternative

(A + B) /. Plus -> List

• I don't think this will work in general. Think about what happens if the elements of A and B are numbers. Commented Jan 8, 2013 at 1:05
• sure. as mentioned: it is just pedagogical in that sense that it is easy to understand and you don't have to use Function with a Null argument. Commented Jan 8, 2013 at 9:34

In the spirit of Rolf Mertig's answer we can abuse a system function with the attribute Listable to effect our join. By simultaneously using an invalid syntax we can avoid undesired evaluation. I chose Re:

threadJoin = Quiet[Re @ ##] /. Re -> List &;


Now:

threadJoin[
{1, 2, 3},
{4, 5, 6}
]

{{1, 4}, {2, 5}, {3, 6}}

threadJoin[
{{a[0, 0], a[1, 0]}, {a[0, 1], a[1, 1]}},
{{b[0, 0], b[1, 0]}, {b[0, 1], b[1, 1]}},
{{c[0, 0], c[1, 0]}, {c[0, 1], c[1, 1]}}
]

{{{a[0, 0], b[0, 0], c[0, 0]}, {a[1, 0], b[1, 0], c[1, 0]}},
{{a[0, 1], b[0, 1], c[0, 1]}, {a[1, 1], b[1, 1], c[1, 1]}}}

threadJoin[
{{{a1, a2, a3}, {b1, b2, b3}, {c1, c2, c3}}, {11, 22, 33}},
{{{a4, a5, a6}, {b4, b5, b6}, {c4, c5, c6}}, {44, 55, 66}}
]

{{{{a1, a4}, {a2, a5}, {a3, a6}}, {{b1, b4}, {b2, b5}, {b3, b6}}, {{c1, c4},
{c2, c5}, {c3, c6}}}, {{11, 44}, {22, 55}, {33, 66}}}


From your comment "what if I want to make a[0,0] a list as well?" I think Daniel's Transpose method is the way to go but the second parameter was never generalized. I believe you could use:

elementJoin[a_, b_] :=
Transpose[{a, b}, RotateRight @ Range @ ArrayDepth @ {a, b}]

elementJoin[
{1, 2, 3},
{4, 5, 6}
]

{{1, 4}, {2, 5}, {3, 6}}

elementJoin[
{{1, 2, 3}, {11, 22, 33}},
{{4, 5, 6}, {44, 55, 66}}
]

{{{1, 4}, {2, 5}, {3, 6}}, {{11, 44}, {22, 55}, {33, 66}}}

elementJoin[
{{{a1, a2, a3}, {b1, b2, b3}, {c1, c2, c3}}, {11, 22, 33}},
{{{a4, a5, a6}, {b4, b5, b6}, {c4, c5, c6}}, {44, 55, 66}}
]

{{{{a1, a2, a3}, {a4, a5, a6}}, {{b1, b2, b3}, {b4, b5, b6}},
{{c1, c2, c3}, {c4, c5, c6}}}, {{11, 44}, {22, 55}, {33, 66}}}


Note that this last output is not the same as that produced by R.M's Listable function:

Function[, {##}, Listable][
{{{a1, a2, a3}, {b1, b2, b3}, {c1, c2, c3}}, {11, 22, 33}},
{{{a4, a5, a6}, {b4, b5, b6}, {c4, c5, c6}}, {44, 55, 66}}
]

{{{{a1, a4}, {a2, a5}, {a3, a6}}, {{b1, b4}, {b2, b5}, {b3, b6}}, {{c1, c4},
{c2, c5}, {c3, c6}}}, {{11, 44}, {22, 55}, {33, 66}}}
`

Choose according to your needs.