# How to sort my list?

For example I have two lists of such structure

L1 = {{"Australia",a1}, {"USA",a2}, {"Norway",a3},...}
L2 = {{"Russia",b1}, {"Norway",b2}, {"Japan",b3},...}

I would like to sort countries of the list L2 in the countries' order of L1 to compare it entirely (I mean the values matching for each country). Thus I would like to gain something resembling this as a result where L3 is the sorted L2:

L1 = {{"Australia",a1}, {"USA",a2}, {"Norway",a3},...}
L3 = {{"Australia",b26},{"USA",b13} {"Norway",b2},...}
• Contries are the same for sure. Commented Aug 7, 2014 at 14:29
• Related: (13886), (22599) Commented Aug 7, 2014 at 16:05

l1 = {{"a", a1}, {"b", a2}, {"c", a3}}
l2 = {{"c", b3}, {"b", b2}, {"a", b1}}
{#, # /. Rule @@@ l2} &[l1[[All, 1]]] // Transpose
(*
{{"a", b1}, {"b", b2}, {"c", b3}}
*)
• That's why taking l1 = {{"a", a1}, {"c", a3}, {"b", a2}}; would be a better example :)
– Öskå
Commented Aug 7, 2014 at 14:31

Edit: This question closely related to one asked on Stack Overflow before the existence of Mathematica.SE. Please see this link for the history and examples:

The first Q&A references a use of the Ordering method shown below from 2007 on MathGroup:

(Thanks to belisarius for helping me find this.)

From your declaration "Contries(sic) are the same for sure." follows:

L1 = {{"IsleOfMan", 1}, {"Samoa", 2}, {"Tunisia", 3}, {"Svalbard", 4}, {"NewCaledonia", 5}};
L2 = {{"Tunisia", 1}, {"NewCaledonia", 2}, {"IsleOfMan", 3}, {"Svalbard", 4}, {"Samoa", 5}};

GatherBy[L1 ~Join~ L2, First][[All, 2]]
{{"IsleOfMan", 3}, {"Samoa", 5}, {"Tunisia", 1}, {"Svalbard", 4}, {"NewCaledonia", 2}}

Or correcting eldo's attempt as using Ordering:

Sort[L2][[Ordering @ Ordering @ L1]]
{{"IsleOfMan", 3}, {"Samoa", 5}, {"Tunisia", 1}, {"Svalbard", 4}, {"NewCaledonia", 2}}

Both are much faster than belisarius's method, with Ordering being particularly good:

Edit: Now including Simon Woods' recommendation from the comments as sim.

bel[{l1_, l2_}] := {#, # /. Rule @@@ l2} &[l1[[All, 1]]] // Transpose

wiz[{L1_, L2_}] := GatherBy[L1 ~Join~ L2, First][[All, 2]]

ord[{L1_, L2_}] := Sort[L2][[Ordering @ Ordering @ L1]];

sim[{L1_, L2_}] := L2[[ Ordering[L2][[Ordering @ Ordering @ L1]] ]]

gen[n_] := Table[{RandomSample @ Range @ n, Range @ n}\[Transpose], {2}]

Needs["GeneralUtilities`"]

BenchmarkPlot[{bel, wiz, ord, sim}, gen, 2^Range[20],
"IncludeFits" -> True, ImageSize -> 500, PlotRange -> {Automatic, {1*^-6, 1}}]

• For small data it is a little faster to use L2[[Ordering[L2][[Ordering@Ordering@L1]]]] Commented Aug 7, 2014 at 20:09
• @Simon That's a lot of Ordering! Let me add it to the timings. :-) Commented Aug 7, 2014 at 20:10
• @Simon BenchmarkPlot doesn't seem to show much difference. Can you give me an example where the difference is more apparent? Commented Aug 7, 2014 at 20:19
• Hmm, I saw a fairly consistent difference for small n but after a restart it has gone away! Commented Aug 7, 2014 at 20:42
• Interesting! Now we need to find 10^5 countries to try it out. Commented Aug 7, 2014 at 23:42
L1 = {{"Australia", a1}, {"USA", a2}, {"Norway", a3}};
L2 = {{"USA", b1}, {"Norway", b2}, {"Australia", b3}};

L2[[Flatten[Position[First /@ L2, #] & /@ First /@ L1]]]

{{"Australia", b3}, {"USA", b1}, {"Norway", b2}}

Or (revised as per Mr. Wizard's comments)

Sort[L2][[Ordering @ Ordering @ L1]]

{{"Australia", b3}, {"USA", b1}, {"Norway", b2}}

• Unfortunately Sort[L2][[Ordering[L1]]] does not appear to work. Commented Aug 7, 2014 at 16:40
• @Mr.Wizard With me it produces the output shown in my answer. Please clarify
– eldo
Commented Aug 7, 2014 at 16:47
• Actually I just remembered something; THIS does work: Sort[L2][[Ordering @ Ordering @ L1]], and I think it will help me find my elusive duplicate. Commented Aug 7, 2014 at 16:52
• @Mr.Wizard Thanks, I updated
– eldo
Commented Aug 7, 2014 at 17:00
• @Mr.Wizard Perhaps the comment under this answer mathematica.stackexchange.com/a/31266/193 Commented Aug 7, 2014 at 19:25
L1 = {{"Australia", a1}, {"Norway", a2}, {"USA", a3}, {"Russia", a4}, {"Japan", a5}} ;
L2 = {{"Russia", b1}, {"Norway", b2}, {"Japan", b3}};

x = First /@ L1;

y = Cases[L2, {#, _}] & /@ x;

z = Apply[Sequence, y, {2}] /. {} -> "";

Grid[Prepend[Transpose[{L1, z}], {"L1", "L3"}], Frame -> All]

Edit

For speed, create y like so :--

getSubset[input_List, sub_List] := Module[{test},
(test@# = True) &~Scan~sub;
Apply[Sequence, Reap[Cases[input, x : {y_?test, ___} :> x~Sow~y], sub][[2]], {2}]]

y = getSubset[L2, x]

Timing Tests

test = Range[10000];
L1 = Transpose[{test, test}];
L2 = RandomSample[L1, 10000];

Row[{First@Timing[x = First /@ L1;
y = Cases[L2, {#, _}] & /@ x;
z = Apply[Sequence, y, {2}] /. {} -> ""], " seconds"}]

46.457098 seconds

Row[{First@Timing[x = First /@ L1;
y = getSubset[L2, x];
z = Apply[Sequence, y, {2}] /. {} -> ""], " seconds"}]

0.124801 seconds

Row[{First@Timing[
{#, # /. Rule @@@ L2} &[L1[[All, 1]]]], " seconds"}]

1.372809 seconds

Row[{First@Timing[
L2[[Flatten[Position[First /@ L2, #] & /@ First /@ L1]]]], " seconds"}]

5.163633 seconds

SortBy[l2, Position[l1, #1 [[1]]] [[1, 1]] &]

• There's no need to extract the number from the position result: SortBy[l2, Position[l1, First@#]&] Commented Aug 7, 2014 at 19:46

While there are a number of replies with ways of ordering the two lists, let me give a different approach to comparing two sets of data of the form you gave. This applies if you are using v10 as it uses Associations.

Here's the data eldo used

l1 = {{"Australia", a1}, {"USA", a2}, {"Norway", a3}};
l2 = {{"USA", b1}, {"Norway", b2}, {"Australia", b3}};

Construct two Associations:

{assoc1, assoc2} = (Association[Rule @@@ #] & /@ {l1, l2})

(*
{<|"Australia" -> a1, "USA" -> a2, "Norway" -> a3|>, <|"USA" -> b1,
"Norway" -> b2, "Australia" -> b3|>}
*)

The advantage is that you can now use the countries as keys, and there is no need to worry about ordering. Here are the keys:

Keys@assoc1
(*{"Australia", "USA", "Norway"}*)

Here is one way to check all of them for equality:

{#, assoc1[#] == assoc2[#]} & /@ Keys[assoc1]

Using Mathematica 10's associations makes this simple.

l1 = {{"Australia", a1}, {"USA", a2}, {"Norway", a3}, {"Russia", a4}, {"Japan", a5}};

Convert the second list to an association

l2 = Association@((#[[1]] -> #[[2]]) & /@ {{"Russia", b1}, {"Norway", b2}, {"Japan", b3}, {"Australia", b4}, {"USA", b5}});

Apply the association rules

l3 = ReplaceAll[l1, {x_, y_} :> {x, l2[x]}]

Lookup is working also.

l1 = {{"Australia", a1}, {"USA", a2}, {"Norway", a3}};
l2 = {{"USA", b1}, {"Norway", b2}, {"Australia", b3}};
{First@#, Lookup[Rule @@@ l2, First@#]} & /@ l1

or

{#, Lookup[Rule @@@ l2, #]} & /@ l1[[;; , 1]]

(*{{"Australia", b3}, {"USA", b1}, {"Norway", b2}}*)