# Behavior of Inner depends on List dimensions?

Consider the following case:

list1 = {q, r, s};
list2 = {{a, 2}, {b, 3}, {c, 1, f}};
Inner[{#1, #2} &, list1, list2, List]
(* Out[] := {{q, {a, 2}}, {r, {b, 3}}, {s, {c, 1, f}}} *)


However, if the last element of list2 has Length 2:

list1 = {q, r, s};
list2 = {{a, 2}, {b, 3}, {c, 1}};
Inner[{#1, #2} &, list1, list2, List]
(* Out[] := {{{q, a}, {r, b}, {s, c}}, {{q, 2}, {r, 3}, {s, 1}}} *)


I would have expected (and wanted) a result like:

(* Out[] := {{q, {a, 2}}, {r, {b, 3}}, {s, {c, 1}}} *)


So,

1. Why does this Inner operation change if the list2 entries are all of the same length?
2. How can I generate an output like the expected result?

Edit I came up with a potential answer to question 2:

Partition[Riffle[list1, list2], 2]
Out[] := {{q, {a, 2}}, {r, {b, 3}}, {s, {c, 1}}}


but this seems somehow too-complicated.

-
Inner[] in your second case is just being consistent with the behavior of Dot[]; contrast with {q, r, s}.{{a, 2}, {b, 3}, {c, 1}}. –  Guess who it is. Aug 8 '12 at 16:08

Inner is a generalization of Dot, and Dot has specific behavior for vectors, matrices and tensors:

{a, b, c} . {x[1, 2], x[3, 4], x[5, 6]}

{a, b, c} . {{1, 2}, {3, 4}, {5, 6}}

a x[1, 2] + b x[3, 4] + c x[5, 6]

{a + 3 b + 5 c, 2 a + 4 b + 6 c}


When Inner detects a complete tensor it changes behavior in a similar fashion.
Likewise the second and third arguments of Inner are order-dependent like the arguments of Dot.

Just as x was used in Dot above, one can use an arbitrary head to "shield" the tensor depth from Inner. Unevaluated is a nice choice in this case because it will be automatically stripped by &.

list1 = {q, r, s};
list2 = {{a, 2}, {b, 3}, {c, 1}};

Inner[{#1, #2} &, list1, Unevaluated /@ list2, List]

{{q, {a, 2}}, {r, {b, 3}}, {s, {c, 1}}}


Another option would be:

Inner[{#, #2[[1]]} &, list1, "" /@ list2, List]


As already mentioned by J. M., for #2:

{list1, list2}\[Transpose]

{{q, {a, 2}}, {r, {b, 3}}, {s, {c, 1}}}

-
+1. It's probably a good idea to use MapAt with Unevaluated since you only need one modification for it to stop being a full array –  Rojo Aug 9 '12 at 0:29
@Rojo that could work but Unevaluated is not a general solution (for example with List in place of {#1, #2} & which does not evaluate) so I think the second method may be more appropriate, and doing that for only one element would complicate things. (thanks for the vote.) –  Mr.Wizard Aug 9 '12 at 3:18
I see your point. Perhaps this as ugly as it is could be more general Inner[List, list1, #, List] &[ MapAt[Sequence, Unevaluated[#] &[list2], {1, 1}]]. More general is still not general. It wouldn't work with HoldComplete instead of the first List –  Rojo Aug 9 '12 at 3:32
+1 That makes sense. Thanks! –  Eli Lansey Aug 9 '12 at 11:12

I came up with a better answer to the second part of my question:

Thread[{list1, list2}]
(* Out[] := {{q, {a, 2}}, {r, {b, 3}}, {s, {c, 1}}} *)


which works equally well if the entries in the lists are of different lengths.

-
I'd use Transpose[{list1, list2}] myself. –  Guess who it is. Aug 8 '12 at 16:10