# How to create a new list by finding the ratios of two other lists?

Suppose we have two lists:

data1 = {{1, 34}, {2, 54}, {3, 66}, {4, 77}, {5, 92}}
data2 = {{1, 1456}, {2, 1367}, {3, 2080}, {4, 1998}, {5, 1035}}


I'd like to create a new list such that

result = {{1, 34/1456}, {2, 54/1367}, {3, 66/2080}, {4, 77/1998}, {5, 92/1035}}


So, we only need to divide the second members of each pair; the first members remain unchanged.

• You could use something like data1[[All, 2]] to extract the second parts of each pair, divide, and then use Transpose[] to reassemble. Commented May 18, 2020 at 16:53

If the elements appear in order:

MapThread[{First[#], Last[#]/Last[#2]} &, {data1, data2}]


If the elements may appear out of order (i.e. the first element in data1 may not correspond to the first element in data2):

{First[#], Last[#]/Last[#2]} & @@@ GatherBy[Join[data1, data2], First]


If they appear in order and you don't care about creating a variable or modifying an existing one:

data = data1; (* Creates a copy *)
data[[All, 2]] /= data2[[All, 2]];


Or if you want to use rules (this is mostly because we can - it's not necessarily something we should do):

ReplaceList[{data1, data2}, {
{___, {i_, v1_}, ___},
{___, {i_, v2_}, ___}
} :> {i, v1/v2}]


This rule-based one works if the elements appear out order.

Here's another one:

List @@@ Normal[
Association @@ Rule @@@ data1/Association @@ Rule @@@ data2
]


This has an object oriented feel to it and is for those that want to learn about UpValues:

f /: f[i_, j_]/f[i_, k_] := {i, j/k}
f @@@ data1/f @@@ data2

• awesome answer, my friend! There is much usefulness here for me to learn, and many nuances of usage displayed... Thank you for spending the time to share this with us all. Commented May 18, 2020 at 17:32
• @FrancisfromResponseBase Thank you, I’m glad you found it useful! Commented May 18, 2020 at 19:29
Normal @ First @ Ratios[TimeSeries /@ {data2, data1}]

 {{1, 17/728}, {2, 54/1367}, {3, 33/1040}, {4, 77/1998}, {5, 4/45}}


Or define a function:

ClearAll[rF]
rF = Normal @* First @* Ratios @* Map[TimeSeries] @* Reverse;

rF @ {data1, data2}


Normal@ rF @ {data1, data2}


{{1, 17/728}, {2, 54/1367}, {3, 33/1040}, {4, 77/1998}, {5, 4/45}}

Or use the property "Path":

rF[{data1, data2}]["Path"]

 {{1, 17/728}, {2, 54/1367}, {3, 33/1040}, {4, 77/1998}, {5, 4/45}}


as J.M suggested, you can write

Transpose[{data1[[;; , 1]],data1[[;; , 2]] / data2[[;; , 2]]}]


• (+1) Or, as a 'just for fun' alternative: Transpose[{data1.{1,0},data1.{0,1}/data2.{0,1}}] Commented May 18, 2020 at 17:38
a = {{1, 34}, {2, 54}, {3, 66}, {4, 77}, {5, 92}};

b = {{1, 1456}, {2, 1367}, {3, 2080}, {4, 1998}, {5, 1035}};


Using Merge and MapApply (new in 13.1)

c = Merge[Ratios] @ MapApply[Rule] @ Join[b, a]


<|1 -> {17/728}, 2 -> {54/1367}, 3 -> {33/1040}, 4 -> {77/1998}, 5 -> {4/45}|>

Convert to list

KeyValueMap[List] @ c


{{1, {17/728}}, {2, {54/1367}}, {3, {33/1040}}, {4, {77/1998}}, {5, {4/45}}}

Using SequenceReplace with Riffle:

For lists with the same length:

data1 = {{1, 34}, {2, 54}, {3, 66}, {4, 77}, {5, 92}};
data2 = {{1, 1456}, {2, 1367}, {3, 2080}, {4, 1998}, {5, 1035}};

SequenceReplace[{{a_, b_}, {a_, c_}} :> {a, Defer[b/c]}]@
Riffle[data1, data2]


Using SequenceReplace with Transpose:

SequenceReplace[{{{a_, b_}, {a_, c_}}} :> {a, Defer[b/c]}]@
Transpose[{data1, data2}]
`

Result:

{{1, 34/1456}, {2, 54/1367}, {3, 66/2080}, {4, 77/1998}, {5, 92/1035}}