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.

I'm looking for the best function to apply the product of the last two elements of sublist elements to each element:

Example:

(*Input:*)
 {{x1, y1, z1}, {x2, y2, z2}, ...}  

(*Desired output:*)
{{x1, y1, z1, y1 z1}, {x2, y2, z2, y2 z2}, ...}  

I know I could just use a Do loop with an index k and do it element by element with AppendTo, but I guess there is a faster method.

share|improve this question

7 Answers 7

up vote 9 down vote accepted

My proposition:

list = RandomReal[1., {100000, 3}];

newlist = Transpose[{Sequence @@ Transpose[list],
    list[[All, 2]] list[[All, 3]]}];

A little benchmark using other answers:

In[51]:= list = RandomReal[1., {1000000, 3}];

In[52]:= newlist = 
   Transpose[{Sequence @@ Transpose[list], 
     list[[All, 2]] list[[All, 3]]}]; // AbsoluteTiming

Out[52]= {0.056405, Null}

In[53]:= newlist2 = {##, Times[##2]} & @@@ list; // AbsoluteTiming

Out[53]= {0.970229, Null}

In[54]:= newlist3 = 
   Append[#, #[[2]] #[[3]]] & /@ list; // AbsoluteTiming

Out[54]= {0.454465, Null}

In[55]:= insertHereThis[list_List, here_Integer, this_] := 
 Insert[#, this[#], here] & /@ list

In[56]:= newlist4 = 
   insertHereThis[list, 2, #[[2]] #[[3]] &]; // AbsoluteTiming

Out[56]= {0.438192, Null}

In[57]:= func = Join[#, Partition[#[[All, -1]] #[[All, -2]], 1], 2] &;

In[58]:= newlist5 = func[list]; // AbsoluteTiming

Out[58]= {0.053084, Null}

In[60]:= newlist6 = 
   ArrayFlatten[{{#, Transpose[{times[#, 2, 3]}]}}] &[
    list]; // AbsoluteTiming

Out[60]= {0.022477, Null}

EDIT: Added new answer (Mr.Wizard's), which now is the fastest in my machine.

EDIT2: Added Leonid's compiled version, and he is right, it is twice faster!

share|improve this answer

For example

list = RandomInteger[100, {15, 3}]
{{93, 38, 76}, {72, 28, 8}, {4, 51, 96}, {52, 28, 26},
   {37, 73, 93}, {33, 32, 61}, {11, 64, 96}, {28, 97, 11}, 
   {74, 76, 0}, {83, 4,  9}, {31, 85, 15}, {38, 34, 27}, 
   {42, 54, 75}, {47, 45, 78}, {87, 27, 94}}
Append[#, #[[2]] #[[3]]] & /@ list
{{93, 38, 76, 2888}, {72, 28, 8, 224}, {4, 51, 96, 4896}, 
   {52, 28, 26, 728}, {37, 73, 93, 6789}, {33, 32, 61, 1952}, 
   {11, 64, 96, 6144}, {28, 97, 11, 1067}, {74, 76, 0, 0}, 
   {83, 4, 9, 36}, {31, 85, 15, 1275}, {38, 34, 27, 918}, 
   {42, 54, 75, 4050}, {47, 45, 78, 3510}, {87, 27, 94, 2538}}
share|improve this answer

Can use ReplaceAll:

   list = {{a, b, c}, {e, f, g}};
   list /. {x_, y_, z_} -> {x, y, z, y z}

Or Insert:

   ins=Insert[#, #[[2]] #[[3]], -1]&;
   ins/@list

Both give

 {{a, b, c, b c}, {e, f, g, f g}} 

For inserting a function of the data in a row in a column of your choice, define

  insertHereThis[list_List, here_Integer, this_] := 
   Insert[#, this[#], here] & /@ list

and use it as:

  insertHereThis[list, 2, #[[[2]]#[[3]]&]

to get

{{a, b c, b, c}, {e, f g, f, g}}

or as

  insertHereThis[list, 3, 5 &]

to get

{{a, b, 5, c}, {e, f, 5, g}}
share|improve this answer

You could use Apply for this, e.g.

list = Transpose[{Range[10], RandomInteger[10, 10], RandomReal[1, 10]}];

{##, Times[##2]} & @@@ list
share|improve this answer
2  
Note that Apply does not in general benefit from auto-compilation, in contrast to Map (I mention this since efficiency was mentioned in the question's title). –  Leonid Shifrin Mar 7 '12 at 15:41

I propose:

func = Join[#, Partition[#[[All, -1]] #[[All, -2]], 1], 2] &;

func @ {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
{{1, 2, 3, 6}, {4, 5, 6, 30}, {7, 8, 9, 72}}
share|improve this answer
    
I edited my answer to include yours in my benchmarks, now yours is the winner :). –  FJRA Mar 7 '12 at 15:55

If you are looking for the ultimate speed, you can use a custom compiled multiplication function, such as

times  = 
  Compile[{{lst, _Real, 2}, {indi, _Integer}, {indj, _Integer}},
     Module[{res = Table[0., {Length[lst]}]},
       Do[res[[i]] = 
           Compile`GetElement[lst, i, indi]*
           Compile`GetElement[lst, i, indj], 
         {i, Length[lst]}
       ];
       res],
     CompilationTarget -> "C", RuntimeOptions -> "Speed"]

Then,

ArrayFlatten[{{#, Transpose[{times[#, 2, 3]}]}}] &[list]

will do the job. My benchmarks on large lists show that this is about twice faster than the much more elegant version of @Mr.Wizard, which is the fastest of the already posted solutions. The reason it is faster is that I save on one column extraction (such as list[[All,2]]), which is a costly operation, by doing multiplication in-place.

share|improve this answer
    
Leonid, how does this compare to Rojo's method on your system? –  Mr.Wizard Mar 8 '12 at 7:53
    
@Mr.Wizard Mine is still about 1.5 - 2x faster. The idea on double-Transpose did cross my mind, but I somehow dismissed it without even trying. Mat be that was a mistake. –  Leonid Shifrin Mar 8 '12 at 10:28

Here's my innocent but quite efficient

mifunc = Transpose[Append[#, #[[-1]] #[[-2]]]&[Transpose[#]]] &;

Which can also be written:

Append[#, #[[-1]] #[[-2]]] &[#\[Transpose]]\[Transpose] &

Which appears in a Notebook as:

Mathematica graphics

share|improve this answer
    
Wow, that's a lot faster than I expected. Nicely done! –  Mr.Wizard Mar 8 '12 at 7:52

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.