# Loop over a list of lists and apply a function with different arguments for each list

I have optical spectra in the following format:

spectra = {{x1,y1},{x2,y2},...,{xn,yn}}


Where x are wavenumbers and y is intensity. I want to modify my intensity, e.g. divide by 3. So I use the following code for that:

modyfiedspectra = Transpose[{spectra[[All, 1]], spectra[[All, 2]]/3}]


But when I have a list of different spectra, I don't know how to loop over it. For example I have a list of 2 spectra:

listofspectra = {{{x1,y1},{x2,y2},...,{xn,yn}},{{x1,y1},{y2,y2},...,{xn,yn}}}


And now I want to divide intensity of each spectra by different numbers. E.g:

divideby = {3,5}


So, output should be something like that:

(*{{{x1,y1/3},{x2,y2/3},...,{xn,yn/3}},{{x1,y1/5},{x2,y2/5},...,{xn,yn/5}}}*)


So the question: how to loop over a list of lists and apply a function with different arguments for each list?

Very similar to @march answer:

Given for example

listofspectra = {{{x1, y1}, {x2, y2}}, {{x11, y11}, {y22, y22}}};
divideby = {3, 5};


you start defining the function that will modify one spectra :

modifyspectra[spectra_, factor_] :=
Transpose[{spectra[[All, 1]], spectra[[All, 2]]/factor}]


then you apply it to the list of spectras and corresponding factors :

modifyspectra @@@ Thread@{listofspectra, divideby}
(* Apply[modifyspectra, Thread[{listofspectra, divideby}], 1] *)


{{{x1, y1/3}, {x2, y2/3}}, {{x11, y11/5}, {y22, y22/5}}}

You can also use this very similar form (the arguments of the function is now a list containing the same former arguments):

modifyspectra2[{spectra_, factor_}] :=
Transpose[{spectra[[All, 1]], spectra[[All, 2]]/factor}]

modifyspectra2 /@ Thread@{listofspectra, divideby}
(* Map[modifyspectra2, Thread@{listofspectra, divideby} ] *)


{{{x1, y1/3}, {x2, y2/3}}, {{x11, y11/5}, {y22, y22/5}}}

By the way, Thread@{listofspectra, divideby} can also be replaced with Transpose@{listofspectra, divideby}

• I was right this moment trying to come up with a solution using Thread instead of MapThread in order to avoid a bunch of nested pure functions. +1. Oct 16, 2015 at 20:24
• Thanks, that works fine. One small question: what i should do if i want not just divide by any factor but want apply function with different arguments (list of arguments) to different spectra? E.g. i have function for bose-correction of my spectra, nba[wavenuber_,temperature_]:=... and i want use it as argument in your modifyspectra function. Oct 19, 2015 at 12:25
• I'm so sorry, i made a mistake. I realize how to did it! Thank you again! Oct 19, 2015 at 13:15

Here's some versions. The first generalizes your method:

MapThread[Transpose[{#2[[All, 1]], #2[[All, 2]]/#1}] &, {divideby, listofspectra}]
MapThread[Function[{x}, {1, 1/#1} x] /@ #2 &, {divideby, listofspectra}]


Another slight variation:

f[num_, list_] := MapAt[#/num &, list, {All, 2}]


Significantly different:

{1, 1/#} & /@ divideby # & /@ Transpose@listofspectra // Transpose

lst = {{{"a", 1}, {"b", 2}, {"c", 3}}, {{"d", 10}, {"e", 20}, {"f", 30}, {"g", 40}}};

div[li_, di_] := li /. {a_, b_} :> {a, b/di}

MapThread[div, {lst, {3, 5}}]


{{{"a", 1/3}, {"b", 2/3}, {"c", 1}}, {{"d", 2}, {"e", 4}, {"f",
6}, {"g", 8}}}

If it's a one off kind of thing then I find just rewriting the values in the list easier.

listofspectra = {{{x1,y1},{x2,y2},{x3,y3}},{{a1,b1},{a2,b2},{a3,b3}}};

listofspectra[[1, All, 2]] = listofspectra[[1, All, 2]]/3


{{{x1, y1/3}, {x2, y2/3}, {x3, y3/3}}, {{a1, b1}, {a2, b2}, {a3, b3}}}

listofspectra[[2, All, 2]] = listofspectra[[2, All, 2]]/5


{{{x1, y1/3}, {x2, y2/3}, {x3, y3/3}}, {{a1, b1/5}, {a2, b2/5}, {a3, b3/5}}}

But the MapThread method in eldo's answer is more general.

• @JackLaVigne yes I did. Thanks for pointing it out. I've edited my answer Oct 16, 2015 at 23:22

Generally, I do this with MapIndexed as the position information it passes to the function can be used to look up the values you need. For instance,

lst = {{{a1, b1}, {a2, b2}, {a3, b3}}, {{c1, d1}, {c2, d2}, {c3, d3}}};
factors = <|{1, 2} -> 3, {2, 2} -> 5|>;
MapIndexed[#1/Lookup[factors, Key@#2[[{1, 3}]], 1]&, lst, {-1}]
(*
{{{a1, b1/3}, {a2, b2/3}, {a3, b3/3}},
{{c1, d1/5}, {c2, d2/5}, {c3, d3/5}}}
*)