13
$\begingroup$

Consider a table

tab = Table[{i,i^2,i^3,i^5,i^0.3,i^0.7},{i,0.2,3,0.1}];

I would like to multiply the 2rd and 5rd columns by some number. This is how I do it:

a = 2
{#[[1]],a*#[[2]],#[[3]],#[[4]],a*#[[5]],#[[6]]}&/@tab

However, such syntax becomes really annoying if the table would have many columns:

{...,a*#[[K]],...,a*#[[M]],...}&/@tab

where K,M are some numbers. How can I multiply the columns in a more compact way? I.e., what is an analog of ... in Mathematica?

$\endgroup$
0

6 Answers 6

18
$\begingroup$

The simplest method I can think off, is with Query:

Query[All, Thread[{2, 5} -> Function[a * #]]] @ tab
$\endgroup$
1
  • 2
    $\begingroup$ (+1, days ago!) It appears that in this case Query 'compiles' into a right-composition of the operator form of MapAt: Query[All, Thread[{2,5} -> Function[a * #]]]//Normal (* MapAt[a*#1 & , {All, 5}] /* MapAt[a*#1 & , {All, 2}] *) $\endgroup$
    – user1066
    Jun 10, 2022 at 14:06
19
$\begingroup$

Another option could be

a*tab[[All, {2, 5}]]

Which will multiply columns 2 and 5 by a. To replace the original matrix just do

tab[[All, {2, 5}]] = a*tab[[All, {2, 5}]];
$\endgroup$
2
  • 9
    $\begingroup$ also: tab[[All, {2, 5}]] *= a $\endgroup$
    – WReach
    Jun 8, 2022 at 14:33
  • $\begingroup$ easy for biginners $\endgroup$ Jun 14, 2022 at 23:04
11
$\begingroup$

Using the Dot product:

tab.DiagonalMatrix[{1,2,1,1,2,1}]

Or, if there are a lot of columns:

Edit

Lucas Lang suggested a neat modification, such as the following, to the original SparseArray answer (and thanks!):

tab.DiagonalMatrix[SparseArray[Thread[{2,5}->2], {6},1]]

Original answer

tab.SparseArray[{{2,2}->2, {5,5}-> 2,Band[{1, 1}] -> 1}, {6,6}]

With Inner:

Inner[Times, tab, {1,2,1,1,2,1}, List]

In addition, if the table consists of only two columns (a table of {x,y} values, maybe) and if it is desired to multiply all y-values by 2:

table.{{1,0},{0,2}}

For example:

tab[[All,;;2]].{{1,0},{0,2}}

Modify in place using ApplyTo (//=)

(modify tab, not a copy)

tab[[All,{2,5}]]//= 2#&

or using the new function syntax:

tab[[;;,{2,5}]]//=(x |-> 2 x)

Edit 2: ReplaceAt

Since v13.1,ReplaceAt may be used:

result = ReplaceAt[tab,x_ :> 2 x, {All,{2,5}}];

result == tab.DiagonalMatrix[{1,2,1,1,2,1}]

(* True *)      

Edit 3: Threaded

As kglr has taught us (see here and here), an even more convenient method is arguably with Threaded

want = tab.DiagonalMatrix[{1,2,1,1,2,1}];

tab Threaded[{1,2,1,1,2,1}] == want

tab Threaded[SparseArray[Thread[{2,5}->2],6,1]] == want

(* True *)
(* True *)

A further example:

myTable = Array[Subscript[a, Row[{##}]] &, {3, 6}];
myTable//TeXForm

$$ \left( \begin{array}{cccccc} a_{11} & a_{12} & a_{13} & a_{14} & a_{15} & a_{16} \\ a_{21} & a_{22} & a_{23} & a_{24} & a_{25} & a_{26} \\ a_{31} & a_{32} & a_{33} & a_{34} & a_{35} & a_{36} \\ \end{array} \right) $$

myTable Threaded[SparseArray[Thread[{2,5}->2],Dimensions@myTable[[2]],1]]

$$ \left( \begin{array}{cccccc} a_{11} & 2 a_{12} & a_{13} & a_{14} & 2 a_{15} & a_{16} \\ a_{21} & 2 a_{22} & a_{23} & a_{24} & 2 a_{25} & a_{26} \\ a_{31} & 2 a_{32} & a_{33} & a_{34} & 2 a_{35} & a_{36} \\ \end{array} \right) $$

myTable Threaded[SparseArray[{2->2,3->10,6->100},Dimensions@myTable[[2]],1]]

$$ \left( \begin{array}{cccccc} a_{11} & 2 a_{12} & 10 a_{13} & a_{14} & a_{15} & 100 a_{16} \\ a_{21} & 2 a_{22} & 10 a_{23} & a_{24} & a_{25} & 100 a_{26} \\ a_{31} & 2 a_{32} & 10 a_{33} & a_{34} & a_{35} & 100 a_{36} \\ \end{array} \right) $$

$\endgroup$
1
  • 2
    $\begingroup$ You could also use a 1D SparseArray with default value 1, and then use DiagonalMatrix to convert it. That way you can avoid the 2D specifications and the need for Band $\endgroup$
    – Lukas Lang
    Jun 8, 2022 at 11:08
5
$\begingroup$
a = 2; k = 2; m = 5;

Using direct multiplication:

v = ReplacePart[ConstantArray[1, Last@Dimensions@tab], 
  List /@ {k, m} -> a]

{1, 2, 1, 1, 2, 1}

v tab[[#]] & /@ Range[Length@tab] // TableForm

Using MapAt:

MapAt[Times[a #] &, tab, {All, #} & /@ {k, m}] // TableForm

Using SubsetMap:

SubsetMap[Times[a #] &, tab[[#]], {k, m}] & /@ 
  Range[Length@tab] // TableForm
$\endgroup$
1
$\begingroup$
MapAt[a*#&,tab,{{All,2},{All,5}}]
$\endgroup$
1
$\begingroup$

Building a MultiplyByPosition function:

MultiplyByPosition[array_?VectorQ, factor_, positions : {___Integer}] := 
ReplacePart[array, Thread[Rule[Nest[Map[List, #] &, positions, 2], 
Flatten[factor*Extract[array, Nest[Map[List, #] &, positions, 2]]]]]]

MultiplyByPosition[array_?TensorQ, factor_, positions : {___Integer}] := 
Map[MultiplyByPosition[#, factor, positions] &, array]

Testing MultiplyByPosition:

MultiplyByPosition[tab, a, {2, 5}]===Query[All, Thread[{2, 5} -> Function[a*#]]]@tab

(*True*)

Another way using ReplaceAt and SubsetMap:

Transpose@ReplaceAt[{Transpose@tab}, _ -> SubsetMap[a*# &, {2, 5}], 0]

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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