# 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. Aug 7, 2014 at 14:29
• Related: (13886), (22599) 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å
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,
"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]]]] Aug 7, 2014 at 20:09
• @Simon That's a lot of Ordering! Let me add it to the timings. :-) 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? Aug 7, 2014 at 20:19
• Hmm, I saw a fairly consistent difference for small n but after a restart it has gone away! Aug 7, 2014 at 20:42
• Interesting! Now we need to find 10^5 countries to try it out. 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. Aug 7, 2014 at 16:40
• @Mr.Wizard With me it produces the output shown in my answer. Please clarify
– eldo
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. Aug 7, 2014 at 16:52
• @Mr.Wizard Thanks, I updated
– eldo
Aug 7, 2014 at 17:00
• @Mr.Wizard Perhaps the comment under this answer mathematica.stackexchange.com/a/31266/193 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}]]

y = getSubset[L2, x]


Timing Tests

test = Range;
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]] &]

• There's no need to extract the number from the position result: SortBy[l2, Position[l1, First@#]&] 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@((#[] -> #[]) & /@ {{"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}}*)
`