16
$\begingroup$

I have two lists:

u = {{1, 3}, {2, 6}, {3, 9}}
v = {0, 4}

and I want to obtain this list from them:

z = {{{0, 1}, {4, 3}}, {{0, 2}, {4, 6}}, {{0, 3},{4, 9}}}

I guess the solution will make use of Map, Thread, or even MapThread but I've tried every combinaison I can think of with no luck. How can I do it?

$\endgroup$
  • $\begingroup$ You could do something like Transpose[Thread /@ Thread[{v, Transpose[u]}]] $\endgroup$ – Leonid Shifrin Jan 7 '13 at 17:37
  • $\begingroup$ Welcome to Mathematica.SE! I suggest the following: 1) As you receive help, try to give it too, by answering questions in your area of expertise. 2) Read the FAQs! 3) When you see good Q&A, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge. ALSO, remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign` $\endgroup$ – Vitaliy Kaurov Jan 8 '13 at 13:38
  • 4
    $\begingroup$ Related: (3070), (4004), (11298), (13748) -- 4004 is an exact duplicate asked in a slightly unusual way. $\endgroup$ – Mr.Wizard Aug 29 '13 at 6:29

10 Answers 10

13
$\begingroup$

This works:

Transpose[{v, #}] & /@ u
{{{0, 1}, {4, 3}}, {{0, 2}, {4, 6}}, {{0, 3}, {4, 9}}}
$\endgroup$
  • $\begingroup$ Perfect thanks I didn't think about Transpose $\endgroup$ – Sulli Jan 8 '13 at 8:44
13
$\begingroup$
Transpose /@ Tuples[{{v}, u}]
Transpose @@@ Table[{j, i}, {i, u}, {j, {v}}]
Transpose /@ Partition[Riffle[u, {v}, {1, -2, 2}], 2]

(*{{{0, 1}, {4, 3}}, {{0, 2}, {4, 6}}, {{0, 3}, {4, 9}}}*)
$\endgroup$
  • $\begingroup$ Another code equivalent to the third code: Nest[Partition[#, 2] &, Riffle[Flatten[u], v, {1, -2, 2}], 2] $\endgroup$ – M6299 Aug 31 '13 at 11:48
9
$\begingroup$

Another possibility using Outer:

Outer[Composition[Transpose, List], {v}, u, 1][[1]]

(* {{{0, 1}, {4, 3}}, {{0, 2}, {4, 6}}, {{0, 3}, {4, 9}}} *)

I also like using Riffle for this:

Riffle[v, #] ~Partition~ 2 & /@ u
$\endgroup$
9
$\begingroup$

Just to be different:

Thread /@ ArrayFlatten @ {{v, List /@ u}}

Thread /@ Block[{v}, Thread @ {v, u}]

Here is a variation of chyanog's method that is the fastest I have tested on a long u and short v, both packed:

Transpose[Tuples @ {{v}, u}, {1, 3, 2}]

Timings:

SetAttributes[timeAvg, HoldFirst]
timeAvg[func_] := Do[If[# > 0.3, Return[#/5^i]] & @@ Timing@Do[func, {5^i}], {i, 0, 15}]

u = RandomInteger[99, {500000, 7}];
v = RandomInteger[99, 7];

Do[Transpose[{v, #}] & /@ u, {10}]              // timeAvg
Do[Transpose[Tuples@{{v}, u}, {1, 3, 2}], {10}] // timeAvg
0.1342

0.011104

And here are a couple of other, slower, methods (but faster than the first two in this answer):

Transpose[ArrayFlatten@{{v, {u}\[Transpose]}}, {1, 3, 2}]

With[{T = Transpose},
  T[Tuples /@ T@{T@{v}, T@u}]
]

Inner as used by Artes is superior on unpacked data, and ideal for mixed types. However, when compared to the methods above on packed data it falls behind:

Inner[List, v, Transpose@u, List] // timeAvg
0.2028   (* compare 0.1342 and 0.011104 *)
$\endgroup$
  • $\begingroup$ Could you test also my approach? Not to compete, I don't think it could, but to complete the tests :) $\endgroup$ – Kuba Aug 29 '13 at 9:08
  • $\begingroup$ @Kuba I didn't intend to include timings for all methods. Anyway, on this test I'm afraid your method doesn't fare well: it takes 33 seconds. Sadly it's even slower with v length 1500, u length 2500: 300 to 400 times slower than the other two options. Sorry. :-/ $\endgroup$ – Mr.Wizard Aug 29 '13 at 9:36
  • $\begingroup$ That's even slower than I've though! ;) But it is not a big surprise :) $\endgroup$ – Kuba Aug 29 '13 at 9:37
8
$\begingroup$
Inner[List, v, #, List] & /@ u

(*  {{{0, 1}, {4, 3}}, {{0, 2}, {4, 6}}, {{0, 3}, {4, 9}}}  *)
$\endgroup$
8
$\begingroup$

Still another way, using rule-based expression rewriting.

u /. {i_, j_} -> {{v[[1]], i}, {v[[2]], j}} 

{{{0, 1}, {4, 3}}, {{0, 2}, {4, 6}}, {{0, 3}, {4, 9}}}

$\endgroup$
  • 1
    $\begingroup$ i like your solution because it can be easily applied in similar operators. $\endgroup$ – tchronis Aug 29 '13 at 13:06
7
$\begingroup$

It seems the most efficient is a pure Inner approach unlike in the other answer where it is used with Map.

Inner[ {#1, #2} &, v, Transpose @ u, List]

or simply

Inner[List, v, Transpose @ u, List]
{{{0, 1}, {4, 3}}, {{0, 2}, {4, 6}}, {{0, 3}, {4, 9}}}   

Edit

I tested this solution with tag instead of v, where

tag = {a, b, c, d};

In the following we compare efficiency of provided resonable solutions.

Let's define:

rmrf1[tag_, test_] :=  First@AbsoluteTiming[ Riffle[ tag, #] ~ Partition ~ 2 & /@ test]
rmrf2[tag_, test_] :=  First@AbsoluteTiming[ Thread[ {tag, #}] & /@ test]
trMap[tag_, test_] :=  First@AbsoluteTiming[ Transpose[{tag, #}] & /@ test]
Artes2[tag_, test_] := First@AbsoluteTiming[ Inner[List, tag, Transpose @ test, List]]
MrWizChan[tag_, test_] := First@AbsoluteTiming[Transpose[Tuples@{{tag}, test}, {1, 3, 2}]] 

Let's choose some sets of data:

ts1 = RandomInteger[100, {3 10^5, 4}];
ts2 = RandomInteger[100, {10^6, 4}];

now we have:

rmrf1[tag, ts1]
rmrf2[tag, ts1]
trMap[tag, ts1]
MrWizChan[tag, ts1]
Artes2[tag, ts1]    
2.817000
1.386000
1.577000
1.054000
0.438000

and

rmrf1[tag, ts2]
rmrf2[tag, ts2]
trMap[tag, ts2]
MrWizChan[tag, ts2]
Artes2[tag, ts2]
 9.383000
 4.357000
 5.051000
 3.585000
 1.476000

These results clearly demonstrate that the Inner solution is the best, while the other ones (involving mapping Thread, Riffle, Transpose or transposing Tuples) are at least a few times slower. In fact, we get similar results with other data like e.g. RandomReal.

$\endgroup$
  • $\begingroup$ Artes, to be fair you should include timings with a packed array of "tags" i.e. Reals or Integers. If you do not I will add them to my answer, but I will have to use v7 timings. $\endgroup$ – Mr.Wizard Aug 31 '13 at 8:21
  • $\begingroup$ @Mr.Wizard We could restrict to this case since the question didn't concern packed tags and the Inner is the winner. Nonetheless I'll try to add those timings later even though they are not stricly related to our problem. $\endgroup$ – Artes Aug 31 '13 at 8:25
  • $\begingroup$ Well, this question does show integer "tags" but I know that the one you originally answered did not. I think there's plenty of room for both. (Meaning, your optimal method for unpacked data, and Vitaliy's chyanog's and my answers for the packed data.) $\endgroup$ – Mr.Wizard Aug 31 '13 at 8:28
6
$\begingroup$

yet another idea (works as long as long as the "elements" in u, v are not Lists)

Function[, {##}, Listable][v, #] & /@ u
$\endgroup$
5
$\begingroup$

Again, there is no MapIndexed approach:

u = {{1, 3}, {2, 6}, {3, 9}}
v = {0, 4}

MapIndexed[{v[[Last@#2]], #1} &, u, {2}]
$\endgroup$
  • $\begingroup$ you are spending a lot of time out here ;) +1 $\endgroup$ – PlatoManiac Aug 29 '13 at 9:28
  • $\begingroup$ @Plato Kuba and Michael are burning up the scoreboard; I'm running like a mad man to stay ahead of them. :-) Oh, and I can't forget Nasser! This month he's #2. $\endgroup$ – Mr.Wizard Aug 29 '13 at 9:30
  • $\begingroup$ @PlatoManiac I have to study for exams and have other duties so the choice is obvious :) $\endgroup$ – Kuba Aug 29 '13 at 9:31
  • $\begingroup$ @Mr.Wizard “We are all failures- at least the best of us are.” I am always looking for more and more of this madness of yours! Keep running fast like those quasars :-) $\endgroup$ – PlatoManiac Aug 29 '13 at 9:50
1
$\begingroup$

Using the second and third arguments of Thread:

Thread /@ Thread[{v, u}, List, {2}]

{{{0, 1}, {4, 3}}, {{0, 2}, {4, 6}}, {{0, 3}, {4, 9}}}

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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