Многие люди не знают, что Python позволяет фильтровать результаты понимания списка, используя if
:
>>> [i for i in range(10) if i % 2 == 0]
[0, 2, 4, 6, 8]
Я использую это все время при загрузке файлов, разделенных табуляцией, с дополнительными строками комментариев, начинающимися с решетки:
data = [line.strip().split("\t") for line in open("my_file.tab") \
if not line.startswith('#')]
Конечно, это работает и для любого другого комментария и символа-разделителя.
Я часто использую понимания для создания словарных статей:
my_dict = dict((k, some_func(k)) for k in input_list)
Примечание. Python 3 имеет интерпретации dict, поэтому это выглядит следующим образом:
my_dict = {k:some_func(k) for k in input_list}
Для создания CSV-подобных данных из списка кортежей:
data = "\n".join(",".join(x) for x in input)
На самом деле это не понимание списка, но все же полезно: составьте список диапазонов из списка «точек отсечения»:
ranges = zip(cuts, cuts[1:])
Пока вы занимаетесь функциональным программированием, вдохновленным частями Python, рассмотрите возможность сопоставления, фильтрации, сокращения и архивирования - все это предлагается в Python.
Чтобы развернуть список списков:
>>> matrix = [[1,2,3], [4,5,6]]
>>> [x for row in matrix for x in row]
[1, 2, 3, 4, 5, 6]
В настоящее время у меня есть несколько скриптов, которым необходимо сгруппировать набор точек в «уровни» по высоте. Предполагается, что z-значения точек будут свободно группироваться вокруг определенных значений, соответствующих уровням, с большими промежутками между кластерами.
Итак, у меня есть следующая функция:
def level_boundaries(zvalues, threshold=10.0):
'''Finds all elements z of zvalues such that no other element
w of zvalues satisfies z <= w < z+threshold.'''
zvals = zvalues[:]
zvals.sort()
return [zvals[i] for i, (a, b) in enumerate(pairs(zvals)) if b-a >= threshold]
"пары" взяты прямо из документации модуля itertools, но для справки:
def pairs(iterable):
'iterable -> (iterable[n], iterable[n+1]) for n=0, 1, 2, ...'
from itertools import izip, tee
first, second = tee(iterable)
second.next()
return izip(first, second)
Надуманный пример использования (мои фактические наборы данных слишком велики, чтобы использовать их в качестве примеры):
>>> import random
>>> z_vals = [100 + random.uniform(-1.5,1.5) for n in range(10)]
>>> z_vals += [120 + random.uniform(-1.5,1.5) for n in range(10)]
>>> z_vals += [140 + random.uniform(-1.5,1.5) for n in range(10)]
>>> random.shuffle(z_vals)
>>> z_vals
[141.33225473458657, 121.1713952666894, 119.40476193163271, 121.09926601186737, 119.63057973814858, 100.09095882968982, 99.226542624083109, 98.845285642062763, 120.90864911044898, 118.65196386994897, 98.902094334035326, 121.2741094217216, 101.18463497862281, 138.93502941970601, 120.71184773326806, 139.15404600347946, 139.56377827641663, 119.28279815624718, 99.338144106822554, 139.05438770927282, 138.95405784704622, 119.54614935118973, 139.9354467277665, 139.47260445000273, 100.02478729763811, 101.34605205591622, 138.97315450408186, 99.186025111246295, 140.53885845445572, 99.893009827114568]
>>> level_boundaries(z_vals)
[101.34605205591622, 121.2741094217216]
Если "круто" означает безумно, то мне нравится вот это:
def cointoss(n,t):
return (lambda a:"\n".join(str(i)+":\t"+"*"*a.count(i) for i in range(min(a),max(a)+1)))([sum(randint(0,1) for _ in range(n)) for __ in range(t)])
>>> print cointoss(20,100)
3: **
4: ***
5: **
6: *****
7: *******
8: *********
9: *********
10: ********************
11: *****************
12: *********
13: *****
14: *********
15: *
16: **
n и t управляют количеством бросков монеты для каждого теста и количеством раз, когда тест выполняется и строится распределение.
Для транспонирования матрицы mat
:
>>> [list(row) for row in zip(*mat)]
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]