Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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},...}
share|improve this question
1  
Contries are the same for sure. –  David Aug 7 at 14:29
    
Related: (22599) –  Mr.Wizard Aug 7 at 16:05

8 Answers 8

up vote 3 down vote accepted
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}}
*)
share|improve this answer
    
That's why taking l1 = {{"a", a1}, {"c", a3}, {"b", a2}}; would be a better example :) –  Öskå Aug 7 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:

See also:

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

enter image description here

share|improve this answer
    
For small data it is a little faster to use L2[[Ordering[L2][[Ordering@Ordering@L1]]]] –  Simon Woods Aug 7 at 20:09
    
@Simon That's a lot of Ordering! Let me add it to the timings. :-) –  Mr.Wizard Aug 7 at 20:10
    
@Simon BenchmarkPlot doesn't seem to show much difference. Can you give me an example where the difference is more apparent? –  Mr.Wizard Aug 7 at 20:19
    
Hmm, I saw a fairly consistent difference for small n but after a restart it has gone away! –  Simon Woods Aug 7 at 20:42
1  
Interesting! Now we need to find 10^5 countries to try it out. –  belisarius Aug 7 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}}

share|improve this answer
    
Unfortunately Sort[L2][[Ordering[L1]]] does not appear to work. –  Mr.Wizard Aug 7 at 16:40
    
@Mr.Wizard With me it produces the output shown in my answer. Please clarify –  eldo Aug 7 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. –  Mr.Wizard Aug 7 at 16:52
    
@Mr.Wizard Thanks, I updated –  eldo Aug 7 at 17:00
1  
@Mr.Wizard Perhaps the comment under this answer mathematica.stackexchange.com/a/31266/193 –  belisarius Aug 7 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]

enter image description here

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

share|improve this answer

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

share|improve this answer
    
There's no need to extract the number from the position result: SortBy[l2, Position[l1, First@#]&] –  Simon Woods Aug 7 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]
share|improve this answer

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]}]
share|improve this answer

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}}*)
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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