Below are five functions to calculate all permutations of a list. Some are mine, some are borrowed, all are valid.
#! /usr/bin/env python
import time
import matplotlib
import matplotlib.pyplot as plt
def perm1(lst):
if len(lst) == 0:
return []
elif len(lst) == 1:
return [lst]
else:
l = []
for i in range(len(lst)):
x = lst[i]
xs = lst[:i] + lst[i+1:]
for p in perm1(xs):
l.append([x] + p)
return l
def perm2(lst):
if len(lst) == 0:
yield []
elif len(lst) == 1:
yield lst
else:
for i in range(len(lst)):
x = lst[i]
xs = lst[:i] + lst[i+1:]
for p in perm2(xs):
yield [x] + p
# http://stackoverflow.com/questions/2710713/algorithm-to-generate-all-possible-permutations-of-a-list
# from zhywu at stackoverflow.com
def perm3(lst):
if len(lst) <= 2:
yield lst
lst = lst[::-1]
yield lst
else:
l = []
for i in range(len(lst)):
x = lst[i]
xs = lst[:i] + lst[i+1:]
for p in perm3(xs):
yield [x]+p
# from Peter Breuer at stackoverflow (ported from his Haskell implementation)
def perm4(lst):
if len(lst) <= 0:
yield []
elif len(lst) == 1:
yield lst
else:
for p in perm4(lst[1:]):
for a, b in splits(p):
yield a + [lst[0]] + b
# list of ways of splitting a list into two parts
def splits(lst):
for i in xrange(len(lst)+1):
yield [lst[:i], lst[i:]]
# found this on internet, not sure where
def perm5(xs, low=0):
if low + 1 >= len(xs):
yield xs[:]
else:
for p in perm5(xs, low + 1):
yield p
for i in range(low + 1, len(xs)):
xs[low], xs[i] = xs[i], xs[low]
for p in perm5(xs, low + 1):
yield p
xs[low], xs[i] = xs[i], xs[low]
def function_times(fs, maxlen=5):
res = []
for f in fs:
r = []
for i in range(maxlen):
data = range(i)
start = time.time()
for p in f(data):
pass
end = time.time()
r.append(end-start)
res.append(r)
return res
def all_results_equal(fs, data):
p1 = sorted(perm1(data))
p2 = sorted([p for p in perm2(data)])
p3 = sorted([p for p in perm3(data)])
p4 = sorted([p for p in perm4(data)])
p5 = sorted([p for p in perm5(data)])
return p1 == p2 == p3 == p4 == p5
if __name__ == '__main__':
functions = [perm1, perm2, perm3, perm4, perm5]
assert all_results_equal(functions, range(4))
res = function_times(functions, 9)
fig = plt.figure(dpi=90)
ax = fig.add_subplot(111)
for r in res:
ax.plot(r)
ax.legend(['perm1', 'perm2', 'perm3', 'perm4', 'perm5'],
loc='upper center',
#bbox_to_anchor=(0.5, 1.05),
ncol=2, fancybox=True, shadow=True)
ax.set_yscale('log')
plt.title('Permutation function runtimes versus list length')
plt.xlabel('list length')
plt.ylabel('time (seconds)')
plt.show()
Below are two plots of the same data--one using linear y axis, the other using logarithmic y axis. As you can see, the fourth function (teal line) performs slightly better than the rest, for large lists, although none of the functions performs that well on large lists.
No comments:
Post a Comment