6
$\begingroup$

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.

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

5 Answers 5

7
$\begingroup$

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
$\endgroup$
2
  • 3
    $\begingroup$ 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. $\endgroup$ Commented May 18, 2020 at 17:32
  • $\begingroup$ @FrancisfromResponseBase Thank you, I’m glad you found it useful! $\endgroup$
    – C. E.
    Commented May 18, 2020 at 19:29
5
$\begingroup$
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}

enter image description here

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}}
$\endgroup$
5
$\begingroup$

as J.M suggested, you can write

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

updated: removed Thread

$\endgroup$
1
  • 1
    $\begingroup$ (+1) Or, as a 'just for fun' alternative: Transpose[{data1.{1,0},data1.{0,1}/data2.{0,1}}] $\endgroup$
    – user1066
    Commented May 18, 2020 at 17:38
3
$\begingroup$
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}}}

$\endgroup$
2
$\begingroup$

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}}

$\endgroup$

Your Answer

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

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