8
$\begingroup$

I know there are a plenty of other questions here which appear to be similar, however I did not found anything which could give me a hint.

I have two lists:

list1 = {{A, 12}, {B, 10}, {C, 4}}; (*ordered according to the second column*)
list2 = {{B, 5}, {A, 4}, {C, 1}};   (*ordered according to the second column*)

Now I want to sort list2according to the list1-order so the output should be:

(* {{A, 4}, {B, 5}, {C, 1}} *)
$\endgroup$
  • $\begingroup$ to be more specific list2should be sorted according to the first column of list1 $\endgroup$ – M.A. Mar 27 at 18:58
  • 1
    $\begingroup$ Is there a better example to show what you want? Doesn't Sort[list2] give the desired output? $\endgroup$ – Jason B. Mar 27 at 23:24
  • 4
    $\begingroup$ list2[[OrderingBy[list1, -#[[2]] &]]] in the next release... $\endgroup$ – Daniel Lichtblau Mar 27 at 23:37
7
$\begingroup$
Permute[list2, FindPermutation[ list2[[All,1]] , list1[[All,1]] ] ]

{{A, 4}, {B, 5}, {C, 1}}

$\endgroup$
  • $\begingroup$ Actually, I like your solution much better than mine. By the way, when I found out that my former solution was incorrect, I also realized that your solution should better be Permute[list2, FindPermutation[list2[[All, 1]], list1[[All, 1]]]]. $\endgroup$ – Henrik Schumacher Mar 27 at 20:47
  • 1
    $\begingroup$ Doh...fixed it. Both ways give the same answer, which leads to sloppy debugging. $\endgroup$ – MikeY Mar 27 at 21:04
6
$\begingroup$
list1 = {{A, 12}, {B, 10}, {C, 4}, {D, 2}};
list2 = {{A, 4}, {D, 11}, {B, 5}, {C, 1}};

idx = Lookup[
   AssociationThread[list1[[All, 1]] -> Range[Length[list1]]],
   list2[[All, 1]]
   ];
result = list2;
result[[idx]] = list2;
result

{{A, 4}, {B, 5}, {C, 1}, {D, 11}}

$\endgroup$
  • $\begingroup$ works well with the example lists. However, something goes wrong when I use other lists with Strings in the first columns instead of A, Band C.... $\endgroup$ – M.A. Mar 27 at 21:29
5
$\begingroup$

ugly but fast:

list2[[Ordering[list2[[All, 1]]][[Ordering[Ordering[list1[[All, 1]]]]]]]]

{{A, 4}, {B, 5}, {C, 1}}

even faster:

result = list2;
result[[Ordering[list1[[All, 1]]]]] = SortBy[list2, First];
result

{{A, 4}, {B, 5}, {C, 1}}

benchmarks

s = 10^7;
list1 = Transpose[{PermutationList@RandomPermutation[s],
                   RandomInteger[{0, 10}, s]}];
list2 = Transpose[{PermutationList@RandomPermutation[s],
                   RandomInteger[{0, 10}, s]}];

(* my first solution *)
result1 = list2[[Ordering[list2[[All, 1]]][[Ordering[Ordering[list1[[All, 1]]]]]]]]; //AbsoluteTiming//First
(* 8.6416 *)

(* my second solution *)
result2 = Module[{L},
  L = list2;
  L[[Ordering[list1[[All, 1]]]]] = SortBy[list2, First];
  L]; //AbsoluteTiming//First
(* 6.89593 *)

(* MikeY's solution *)
result3 = Permute[list2, FindPermutation[list2[[All, 1]], list1[[All, 1]]]]; //AbsoluteTiming//First
(* 15.808 *)

(* Henrik Schumacher's solution *)
result4 = Module[{idx, L},
  idx = Lookup[AssociationThread[list1[[All, 1]] -> Range[Length[list1]]], list2[[All, 1]]];
  L = list2;
  L[[idx]] = list2;
  L]; //AbsoluteTiming//First
(* 31.7412 *)

(* make sure all methods agree *)
result1 == result2 == result3 == result4
(* True *)
$\endgroup$
  • $\begingroup$ Thanks for the benchmark. I started down the Ordering road, but went for parsimony of expression. Mild bummer that it is at least twice as slow as the best method. $\endgroup$ – MikeY Mar 27 at 23:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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