Python 2.7 - изменить порядок вывода списков с новым ограничением "порядок"
Я знаю некоторые основы в C++, но я новичок в Python.
У меня есть часть рабочего кода (см. Ниже), и я хотел бы добавить ограничение для форматирования его вывода, и я не могу понять, как это сделать...
Позвольте мне сначала объяснить, что делает программа:
У меня есть входной файл colors.csv
которые содержат список цветов, один цвет линии: цвета определяются их именем и колориметрическими координатами X, Y и Z, это выглядит так:
Colorname, X1, Y1, Z1
Colorname2, X2, Y2, Z2
...etc.
Дан любой список координат XYZ, содержащийся в другом входном файле. targets.csv
программа выдаст мне список решений в выходном файле output.txt
Это решение вычисляется сначала триангуляцией облака точек с помощью тетгена, а затем барицентрическими координатами точки в тетраэдре (но здесь все объяснять не имеет значения...)
Решение имеет вид:
target, name0, density0, name1, density1, name2, density2, name3, density3
Всегда есть только 4 имени и связанные плотности.
Это будет выглядеть, например, так:
122 ,PINKwA,0.202566115168,GB,0.718785775317,PINK,0.0647284446787,TUwA,0.0139196648363
123 ,PINKwA,0.200786239192,GB,0.723766147717,PINK,0.0673550497794,TUwA,0.00809256331169
124 ,PINKwA,0.19900636349,GB,0.72874651935,PINK,0.0699816544755,TUwA,0.00226546268446
125 ,OR0A,0.00155317194109,PINK,0.0716160265958,PINKwA,0.195962072115,GB,0.730868729348
126 ,OR0A,0.00409427478508,PINK,0.0726192660009,PINKwA,0.192113520109,GB,0.731172939105
127 ,OR0A,0.00663537762906,PINK,0.073622505406,PINKwA,0.188264968103,GB,0.731477148862
Что бы я хотел сделать сейчас?
По практическим соображениям я хотел бы, чтобы мои результаты следовали определенному порядку. Я хотел бы, чтобы "список приоритетов" управлял порядком name, density
выход.
Моя настоящая программа выводит имена цветов в порядке, который я не понимаю, но в любом случае мне нужно, чтобы эти имена цветов были в определенном порядке, например PINK
всегда должен быть первым PINKwA
второй и т. д.
Вместо:
127 ,OR0A,0.00663537762906,PINK,0.073622505406,PINKwA,0.188264968103,GB,0.731477148862
Я хочу;
127 ,PINK,0.073622505406,PINKwA,0.188264968103,OR0A,0.00663537762906,GB,0.731477148862
Потому что мой список приоритетов гласит:
0, PINK
1, PINKwA
2, OR0A
3, GB
Как я могу просто добавить эту функцию в код ниже? Любая идея?
РЕДАКТИРОВАННЫЙ КОД (работает...):
import tetgen, geometry
from pprint import pprint
import random, csv
import numpy as np
from pprint import pprint
all_colors = [(name, float(X), float(Y), float(Z))
for name, X, Y, Z in csv.reader(open('colors.csv'))]
priority_list = {name: int(i)
for i, name in csv.reader(open('priority.csv'))}
# background is marked SUPPORT
support_i = [i for i, color in enumerate(all_colors) if color[0] == 'SUPPORT']
if len(support_i)>0:
support = np.array(all_colors[support_i[0]][1:])
del all_colors[support_i[0]]
else:
support = None
tg, hull_i = geometry.tetgen_of_hull([(X,Y,Z) for name, X, Y, Z in all_colors])
colors = [all_colors[i] for i in hull_i]
print ("thrown out: "
+ ", ".join(set(zip(*all_colors)[0]).difference(zip(*colors)[0])))
targets = [(name, float(X), float(Y), float(Z), float(BG))
for name, X, Y, Z, BG in csv.reader(open('targets.csv'))]
for target in targets:
name, X, Y, Z, BG = target
target_point = support + (np.array([X,Y,Z]) - support)/(1-BG)
tet_i, bcoords = geometry.containing_tet(tg, target_point)
output = open('output.txt','a')
if tet_i == None:
output.write(str(target[0]))
output.write('\n')
else:
names = [colors[i][0] for i in tg.tets[tet_i]]
sorted_indices = sorted(enumerate(names), key=lambda (i, name): priority_list[name])
output.write(target[0])
counting = 0
for i, name in sorted(enumerate(names), key=lambda (i, name): priority_list[name]):
output.write(',%s,%s' % (name, bcoords[i]))
counting = counting + 1
if counting > 3:
output.write('\n')
counting = 0
output.close()
1 ответ
Во-первых, вам нужно закодировать ваш список приоритетов непосредственно в коде Python:
priority_list = {
'PINK': 0,
'PINKwA': 1,
'OR0A': 2,
'GB': 3,
}
Это позволит вам быстро получить заказ для данного названия цвета. Затем вы можете использовать key
аргумент sorted
сортировать ваши имена по приоритету. Тем не менее, важно, что вам нужно получить не отсортированные имена, а индексы отсортированных имен, так же как http://docs.scipy.org/doc/numpy/reference/generated/numpy.argsort.html.
sorted_indices = sorted(enumerate(names), key=lambda (i, name): priority_list[name])
enumerate
Встроенное аннотирует каждое имя с его индексом в исходном списке имен, а затем sorted
встроенный сортирует полученный (i, name)
пары в зависимости от их ранга в списке приоритетов. Затем мы можем записать имена в файл, за которым следует соответствующий элемент (используя значение индекса) из bcoords
массив.
for i, name in sorted_indices:
output.write(',%s,%s' % (name, bcoords[i]))
Итак, вот что я хотел бы сделать, чтобы последний блок в вашем коде выглядел так:
names = [colors[i][0] for i in tg.tets[tet_i]]
output.write(target[0])
for i, name in sorted(enumerate(names), key=lambda (i, name): priority_list[name]):
output.write(',%s,%s' % (name, bcoords[i]))
output.write('\r\n')
output.close()
Здесь я изменил вашу стратегию вывода файлов, чтобы она была немного более Pythonic - в общем, добавление строк в основном не сделано, лучше вместо этого создать строку формата и заполнить переменные (вы также можете использовать .format()
на строку, чтобы сделать это). Кроме того, вы можете сделать несколько звонков .write()
и они будут просто продолжать записывать байты в файл, поэтому не нужно создавать большую длинную строку сразу для записи. Наконец, не нужно звонить str
на '\r\n'
как это уже строка.