5
$\begingroup$

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},...} 
$\endgroup$
2
  • 1
    $\begingroup$ Contries are the same for sure. $\endgroup$ Commented Aug 7, 2014 at 14:29
  • $\begingroup$ Related: (13886), (22599) $\endgroup$ Commented Aug 7, 2014 at 16:05

8 Answers 8

4
$\begingroup$
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}} *) 
$\endgroup$
1
  • $\begingroup$ That's why taking l1 = {{"a", a1}, {"c", a3}, {"b", a2}}; would be a better example :) $\endgroup$ Commented Aug 7, 2014 at 14:31
4
$\begingroup$

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

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

$\endgroup$
11
  • $\begingroup$ Unfortunately Sort[L2][[Ordering[L1]]] does not appear to work. $\endgroup$ Commented Aug 7, 2014 at 16:40
  • $\begingroup$ @Mr.Wizard With me it produces the output shown in my answer. Please clarify $\endgroup$ Commented Aug 7, 2014 at 16:47
  • $\begingroup$ Actually I just remembered something; THIS does work: Sort[L2][[Ordering @ Ordering @ L1]], and I think it will help me find my elusive duplicate. $\endgroup$ Commented Aug 7, 2014 at 16:52
  • $\begingroup$ @Mr.Wizard Thanks, I updated $\endgroup$ Commented Aug 7, 2014 at 17:00
  • 1
    $\begingroup$ @Mr.Wizard Perhaps the comment under this answer mathematica.stackexchange.com/a/31266/193 $\endgroup$ Commented Aug 7, 2014 at 19:25
2
$\begingroup$
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

$\endgroup$
1
$\begingroup$

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

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

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] 
$\endgroup$
0
$\begingroup$

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]}] 
$\endgroup$
0
$\begingroup$

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}}*) 
$\endgroup$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.