3
$\begingroup$

I have two unequal-length lists of ordered pairs and I want to subtract the y-values one (the bigger one) from the other (the smaller one) if they have the same x value. Ideally, I should end up with a list that is the same size as the smaller one. A simple version of this might be that I'm given

big = {{0,1},{1,10},{2,5},{3,8},{4,9},{5,2}}
small = {{0,-1},{2,1},{5,10}}

And I want to do something such that I get the result

diff = {{0,-2},{2,-4},{5,8}}

So far, from a hodgepodge of other StackExchange answers, I've been trying

f = Composition[Apply[{First@#, Total@#2} &, #] &, Transpose] /@ GatherBy[Join[##], First] &;
big[[All,2]] = big[[All,2]]*(-1)
diff = f[small, big];
diff = DeleteCases[diff, Alternatives @@ big];

(Note: I have the definitions and the operations in difference cells, so I'm not constantly flipping the signs on all the y-values in big)

This gets me close to what I'm looking for, but I don't think it's quite right. With a smaller list like my example it works, but when I'm using bigger lists (mine are 413 and 733 elements long), the resultant list is not the size of the smaller list: it comes out to 474 elements instead. Is there something wrong with what I'm doing, or do I probably just have a typo somewhere in my actual implementation?

$\endgroup$
2
  • $\begingroup$ Are the x-values of small guaranteed to exist as x-values in big? $\endgroup$
    – Coolwater
    Commented Mar 11, 2019 at 21:22
  • $\begingroup$ @Coolwater not necessarily $\endgroup$ Commented Mar 11, 2019 at 21:23

5 Answers 5

4
$\begingroup$

Below I modified big so that it doesn't contain all x-values of small.

big = {{0, 1}, {1, 10}, {2, 5}, {3, 8}, {4, 9}, {6, 2}};
small = {{0, -1}, {2, 1}, {5, 10}};

diff = small;
diff[[All, 2]] -= Total[Nearest[big[[All, 1]] -> big[[All, 2]], small[[All, 1]], {1, 0}], {2}];
diff

{{0, -2}, {2, -4}, {5, 10}}

Alternatively there is

diff[[All, 2]] -= Lookup[Association[Rule @@@ big], small[[All, 1]], 0];
$\endgroup$
1
  • $\begingroup$ This works perfectly, thanks so much! $\endgroup$ Commented Mar 11, 2019 at 21:28
1
$\begingroup$
ClearAll[f]
f = Module[{as1 = AssociationThread[Rule @@ Transpose[#]], 
            as2 = -AssociationThread[Rule @@ Transpose[#2]]}, 
      List @@@ Normal @ Merge[Total] @ {as1, KeyTake[as2, Keys[as1]]}] &

Examples:

f[small, big]

{{0, -2}, {2, -4}, {5, 8}}

f[small, {{0, 1}, {1, 10}, {2, 5}, {3, 8}, {4, 9}, {6, 2}}]

{{0, -2}, {2, -4}, {5, 10}}

$\endgroup$
1
$\begingroup$
KeyValueMap[{#1, Subtract @@ #2} &] @
   DeleteCases[{_}] @ Merge[MapApply[Rule] /@ {small, big}, # &]

{{0, -2}, {2, -4}, {5, 8}}

$\endgroup$
1
$\begingroup$
Clear["Global`*"];
big = {{0, 1}, {1, 10}, {2, 5}, {3, 8}, {4, 9}, {5, 2}};
small = {{0, -1}, {2, 1}, {5, 10}};

brules = Rule @@@ big;
srules = Rule @@@ small;

(KeyIntersection[{srules, brules}] // Merge[Apply[Subtract]] // 
   Normal) /. Rule -> List

{{0, -2}, {2, -4}, {5, 8}}

$\endgroup$
1
$\begingroup$

Another method using Intersection and ReplaceAll:

(Intersection[big, small, SameTest -> (#1[[1]] == #2[[1]] &)] 
// Thread[#[[All, 2]] -> small] &) /. Rule[x_, y : {__}] :> {y[[1]], y[[2]] - x}

 (*{{0, -2}, {2, -4}, {5, 8}}*)
$\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.