2
$\begingroup$

I'm trying to find a code that can quantify the proximity of countries in Europe, taking into account shared borders and I am completely stumped.

So ideally, countries that share a border have a high number and then countries where you have to pass through several borders have a significantly lower score.

Is there also a code which could tell me how many borders one would have to cross to get from country A to country B?

Any help would be greatly appreciated!

$\endgroup$
2
  • 1
    $\begingroup$ By "borders", do you mean geographical borders? $\endgroup$ Mar 12, 2018 at 16:06
  • $\begingroup$ Yes, the shared geographical borders. $\endgroup$ Mar 12, 2018 at 16:08

1 Answer 1

3
$\begingroup$

Update

Inspired by J.M.'s comment I will give a more compact and more functional solution here:

euCountries = CountryData["Europe"];

edges = Inner[
    Function[ {c, listbc}, Sort @ UndirectedEdge[ c, # ]& /@ listbc ],
    euCountries,
    Map[ CountryData[ #, "BorderingCountries" ]&, euCountries ],
    Union
];

g = Graph[ euCountries, edges, VertexLabels -> "Name", ImageSize -> Large ];

Original Solution

A quick an dirty go at this is maybe to build a graph for say Europe with an edge connecting two countries meaning that they are neighbors.

countriesInEurope = CountryData[ "Europe" ];

We then find the neighbors for each country and store them together with the country itself in a list of strings:

listNeighbors = (({#}~Join~CountryData[#, "BorderingCountries"]) & /@ 
countriesInEurope) /. e_Entity :> CountryData[e, "Name"];

We now construct the edges for the graph with taking care of duplicates, so that two countries will only be connected by a single undirected edge:

countryEdges[ list_ ] := With[
   {
     country = First @ list,
     neighbors = Rest @ list
   } ,
   If[ neighbors === {}, Return[Nothing] ];
   Map[ country \[UndirectedEdge] # &, neighbors ]
];

edges = Map[ countryEdges, listNeighbors ] // RightComposition[
   Flatten,
   ReplaceAll[ UndirectedEdge[ a_, b_] :> UndirectedEdge @@ Sort@{a, b}],
   DeleteDuplicates

];

Now we can have our graph:

g = Graph[ Flatten @ listNeighbors, edges, VertexLabels -> "Name" , ImageSize -> Large]

enter image description here

Working With the Graph

We see that there are two countries in between Germany and Croatia:

FindShortestPath[ g, "Germany", "Croatia"]

{"Germany", "Austria", "Hungary", "Croatia"}

We can also have a CountryDistance that would give the number of borders to cross:

countryDistance[a_ , b_ ] := FindShortestPath[ g, a, b] // Length // # - 1 &

countryDistance[ "Germany", "Morocco" ]

3

So with a bit of work more can be done in this line...

$\endgroup$
4
  • 1
    $\begingroup$ Here's a compact version: euCountries = CanonicalName[CountryData["Europe"]]; edges = Union[Flatten[Table[Sort[UndirectedEdge[bord, #]], {bord, CanonicalName[CountryData[#, "BorderingCountries"]]}] & /@ euCountries]]; g = Graph[euCountries, edges, ImageSize -> Large, VertexLabels -> "Name"] $\endgroup$ Mar 13, 2018 at 4:58
  • $\begingroup$ @J.M. Interestingly, one may drop CanonicalName completely in your version as VertexLabels -> "Name" takes care of it. $\endgroup$
    – gwr
    Mar 13, 2018 at 11:07
  • 1
    $\begingroup$ I know, I just preferred storing strings instead of Entity[] objects in the vertices. $\endgroup$ Mar 13, 2018 at 12:39
  • $\begingroup$ Is there a way to make a function for the distance between two countries without using Entities and an Internet connection? $\endgroup$ Apr 6 at 15:44

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.