# Multiplying two dimensional data by a constant

I have a list of lists of the form:

{{1, 2}, {2, 4}, {2, 8}}


But I want to multiply only the second dimension of that data by a constant. I know I could do this with a loop but that is "dirty". There has to be a better way. For example if I multiply the second dimension by 2 I would get:

{{1, 4}, {2, 8}, {2, 16}}

• smartThread[{{1, 2}, {2, 4}, {2, 8}}*{1, 2}]
– ssch
Sep 15, 2013 at 9:59
• Transpose[{1, 2} Transpose[lst]] and ScalingTransform[{1, 2}][lst] are other possibilities. Both from an old MathGroup post by Carl Woll, according to my notes. The first one seems to be very fast. Jan 29, 2018 at 16:18

You can also do it this way:

{{1, 2}, {2, 4}, {2, 8}} /. {x_, y_} -> {x, 2 y}


Which gives:

{{1, 4}, {2, 8}, {2, 16}}


You can change 2 in 2 y to whatever constant you want. This method is flexible because, say you want to multiply the first dimension by a different constant you just put that number in front of x. E.g. Suppose you want to multiply the first dimension by 3 and the second by 2, you simply write:

 {{1, 2}, {2, 4}, {2, 8}} /. {x_, y_} -> {3 x, 2 y}


And this accomplishes the desired task.

EDIT: Using Pure Functions.

{#[[1]], 2 #[[2]]} & /@ {{1, 2}, {2, 4}, {2, 8}}

{First[#], 2 Last[#]} & /@ {{1, 2}, {2, 4}, {2, 8}}

arr = {{1, 2}, {2, 4}, {2, 8}};
arr[[All,2]] *= 2;

• Based on this principle I favor this answer. However, it should be noted that this modifies arr, so a copy should be modified if the original should be unchanged. May 8, 2013 at 2:13

I like to use Apply for this kind of task.

{#1, 2 #2} & @@@ {{1, 2}, {2, 4}, {2, 8}}


Works nicely:

{{1, 2}, {2, 4}, {2, 8}}.DiagonalMatrix[{1, 2}]


DiagonalMatrix[] is particularly convenient for scaling rows or columns.

From whuber:

Multiplying by a diagonal matrix is fast for up to somewhere between 100 and 1000 columns; beyond that, a solution modeled after Transpose[{1, 2} * Transpose[a]] becomes superior. Even better for such large matrices is a . SparseArray[Band[{1, 1}] -> {1, 2}]; this is superior to both once there are 20 columns or so.

• +1. Multiplying by a diagonal matrix is fast for up to somewhere between $100$ and $1000$ columns; beyond that, a solution modeled after Transpose[{1, 2} * Transpose[a]] becomes superior. Even better for such large matrices is a . SparseArray[Band[{1, 1}] -> {1,2}]; this is superior to both once there are $20$ columns or so. May 7, 2013 at 22:06
• @whuber as J. M. made this post wiki please include that comment in the answer. May 8, 2013 at 2:14
Cases[{{1, 2}, {2, 4}, {2, 8}}, {x_, y_} -> {x, 2 y}]

Table[{First@i, Last@i*2}, {i, {{1, 2}, {2, 4}, {2, 8}}}]

{#1, 2 #2} & @@ Transpose@{{1, 2}, {2, 4}, {2, 8}} // Transpose

data = RandomReal[10, {10^6, 2}];
r1 = {#1, 2 #2} & @@ Transpose@data // Transpose; // Timing
r2 = {#1, 2 #2} & @@@ data; // Timing
r1 == r2
(*
{0.109201, Null}
{3.229221, Null}
True
*)


Here's another -general- approach, using MapAt. Maybe not the fastest, but I think it is pretty transparent and configurable:

MapAt[2 # &, list, {1 ;;, 2}]


or (thanks to @RunnyKine)

MapAt[2 # &, list, {All, 2}]


or interestingly, faster:

MapAt[(2 #) &, #, 2] & /@ list


Timings

Using data as in @chyanog's post, I get:

MapAt[2 # &, data, {1 ;;, 2}]; // Timing


{1.078534, Null}

MapAt[(2 #) &, #, 2] & /@ data; // Timing


{0.111480, Null}

(where my machine is about 2x faster than chyanog's, so his solution definitely is faster, by about factor 3) (and it doesn't make sense to compare to all the others, as e.g. DiagonalMatrix is suited for this task very well, but not as configurable)

• +1. You can also use {All, 2} in place of {1;;, 2} with MapAt Sep 15, 2013 at 8:37

As of v13.1, we can also use Threaded:

{{1, 2}, {2, 4}, {2, 8}} Threaded[{1, 2}]
(* {{1, 4}, {2, 8}, {2, 16}} *)


Using ReplaceAt (new in 13.1)

list = {{1, 2}, {2, 4}, {2, 8}};

ReplaceAt[list, x_ :> 2 x, {All, 2}]


{{1, 4}, {2, 8}, {2, 16}}

ReplaceAt has the advantage that we can easily impose additional conditions:

ReplaceAt[list, x_ /; x > 2 :> 2 x, {All, 2}]


{{1, 2}, {2, 8}, {2, 16}}

Using SubsetMap:

list = {{1, 2}, {2, 4}, {2, 8}};
SubsetMap[Times[#, 2] &, list, {All, 2}]


{{1, 4}, {2, 8}, {2, 16}}

To impose more conditions:

SubsetMap[Map[If[# > 2, 2 #, #] &], list, {All, 2}]


{{1, 2}, {2, 8}, {2, 16}}