I want to calculate the difference between two values in a distancetable which is read in from a file, a csv file with a number of cities with distances between them. In the .csv-file I have the first row with cities, like this:
Barcelona;Belgrade;Berlin
The next rows are the distances between the cities, written like this:
0;1528.13;1497.61
1528.13;0;999.25
1497.61;999.25;0
For example, the distance from Barcelona to Barcelona is 0, (first number), Barcelona and Belgrade is 1528.13, (second), Belgrade and Berlin 999.25.. etc
I am trying to create an algorithm to search for the shortest path through all the cities in file like this. But I will need to use Python and probably permutations from itertools.
I don't know how I can use permutations correctly so I can add together the distance from the different possibilites. How can I do this?
So I am importing permutations, csv, reading in the file, and and starting from here...
from itertools import permutations
import csv
# Read data file
distance_table = []
with open('european_cities.csv') as file:
reader = csv.reader(file,delimiter=';')
# First row is the city names
city_names = reader.next()
# The rest of the rows are the distance table
for row in reader:
distance_table.append([float(cell) for cell in row])
so now I can fore example see from the distance_table the distance between city A and city B like this:
distance_table[city_A][city_B]
How can I loop through all combinations in the permutation when I only want each city to appear once??
I want for example: cityA-cityB + cityB-cityC + cityC-cityA and not: cityA-cityB + cityA-cityC + cityB-cityC + cityC-cityA etcetra . . .
I would like to use different algorithms here, firstly a stupid algorithm lie brute force to see the difference in time between this and a smarter algorithm, like the shortest-path algorithm.
But I don't know how I can loop through the cities. How?
You say you want all permutations without any city to appearing twice, yet your example has the starting city (cityA) listed again at the end:
I want for example: cityA-cityB + cityB-cityC + cityC-cityA
So, assuming the first city appearing again at the end is actually what you meant, I think the following shows how you could generate the permutations of cities you want — if that assumption is wrong, simply remove the one line where the first city is duplicated.
In order to get differing total distances (with three it's always the same), I added a fourth city and changed the output format so it's more compact to better accommodate more cities.
Barcelona;Belgrade;Berlin;Brussels
0;1528.13;1497.61;1346.0
1528.13;0;999.25;1723.0
1497.61;999.25;0;764.0
1346.0;1723.0;764.0;0
Here's the code:
from __future__ import print_function
import csv
import functools
try:
from itertools import izip, imap
except ImportError: # Python 3
izip = zip
imap = map
from itertools import permutations, repeat
# Create a distance dictionary from csv data file with entries like this:
# (city_a, city_b): float(distance-between-city_a-and-city_b)
# for all pairs of city names in the file.
data_filename = 'european_cities.csv'
dist_dict = {}
with open(data_filename, 'r') as file:
reader = csv.reader(file, delimiter=';')
cities = next(reader) # header row
num_cities = len(cities)
for city in cities: # should be a row of distances for each city
from_city_iter = repeat(city, num_cities)
dist_dict.update((pair for pair in izip(izip(from_city_iter, cities),
imap(float, next(reader)))
if pair[1])) # skip 0 distances (city_a == city_b)
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2,s3), ..."
a, b = iter(iterable), iter(iterable)
next(b) # advance second iterator one iteration
return izip(a, b)
for tour in permutations(cities, len(cities)):
tour += (tour[0],) # make round trip by appending starting city
route = '->'.join(tour)
dist = sum(dist_dict[city_a, city_b] for city_a, city_b in pairwise(tour))
print('{:^49}: {:,}'.format(route, dist))
Output:
Barcelona->Belgrade->Berlin->Brussels->Barcelona : 4,637.38
Barcelona->Belgrade->Brussels->Berlin->Barcelona : 5,512.74
Barcelona->Berlin->Belgrade->Brussels->Barcelona : 5,565.86
Barcelona->Berlin->Brussels->Belgrade->Barcelona : 5,512.74
Barcelona->Brussels->Belgrade->Berlin->Barcelona : 5,565.86
Barcelona->Brussels->Berlin->Belgrade->Barcelona : 4,637.38
Belgrade->Barcelona->Berlin->Brussels->Belgrade : 5,512.74
Belgrade->Barcelona->Brussels->Berlin->Belgrade : 4,637.38
Belgrade->Berlin->Barcelona->Brussels->Belgrade : 5,565.86
Belgrade->Berlin->Brussels->Barcelona->Belgrade : 4,637.38
Belgrade->Brussels->Barcelona->Berlin->Belgrade : 5,565.86
Belgrade->Brussels->Berlin->Barcelona->Belgrade : 5,512.74
Berlin->Barcelona->Belgrade->Brussels->Berlin : 5,512.74
Berlin->Barcelona->Brussels->Belgrade->Berlin : 5,565.86
Berlin->Belgrade->Barcelona->Brussels->Berlin : 4,637.38
Berlin->Belgrade->Brussels->Barcelona->Berlin : 5,565.86
Berlin->Brussels->Barcelona->Belgrade->Berlin : 4,637.38
Berlin->Brussels->Belgrade->Barcelona->Berlin : 5,512.74
Brussels->Barcelona->Belgrade->Berlin->Brussels : 4,637.38
Brussels->Barcelona->Berlin->Belgrade->Brussels : 5,565.86
Brussels->Belgrade->Barcelona->Berlin->Brussels : 5,512.74
Brussels->Belgrade->Berlin->Barcelona->Brussels : 5,565.86
Brussels->Berlin->Barcelona->Belgrade->Brussels : 5,512.74
Brussels->Berlin->Belgrade->Barcelona->Brussels : 4,637.38