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$
3
  • $\begingroup$ You could do something like Transpose[Thread /@ Thread[{v, Transpose[u]}]] $\endgroup$ Jan 7, 2013 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$ Jan 8, 2013 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, 2013 at 6:29

10 Answers 10

14
$\begingroup$

This works:

Transpose[{v, #}] & /@ u
{{{0, 1}, {4, 3}}, {{0, 2}, {4, 6}}, {{0, 3}, {4, 9}}}
$\endgroup$
1
  • $\begingroup$ Perfect thanks I didn't think about Transpose $\endgroup$
    – Sulli
    Jan 8, 2013 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$
1
  • $\begingroup$ Another code equivalent to the third code: Nest[Partition[#, 2] &, Riffle[Flatten[u], v, {1, -2, 2}], 2] $\endgroup$
    – M6299
    Aug 31, 2013 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$
3
  • $\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, 2013 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, 2013 at 9:36
  • $\begingroup$ That's even slower than I've though! ;) But it is not a big surprise :) $\endgroup$
    – Kuba
    Aug 29, 2013 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
  • 1
    $\begingroup$ i like your solution because it can be easily applied in similar operators. $\endgroup$
    – tchronis
    Aug 29, 2013 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$
3
  • $\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, 2013 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, 2013 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, 2013 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$
4
  • $\begingroup$ you are spending a lot of time out here ;) +1 $\endgroup$ Aug 29, 2013 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, 2013 at 9:30
  • $\begingroup$ @PlatoManiac I have to study for exams and have other duties so the choice is obvious :) $\endgroup$
    – Kuba
    Aug 29, 2013 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$ Aug 29, 2013 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 and acknowledge you have read our privacy policy.

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