Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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.

share|improve this question
    
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}}. –  J. M. Aug 8 '12 at 16:08

2 Answers 2

up vote 7 down vote accepted

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

Mathematica graphics

{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}}}
share|improve this answer
    
+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.

share|improve this answer
5  
I'd use Transpose[{list1, list2}] myself. –  J. M. Aug 8 '12 at 16:10

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.