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' как это уже строка.

Другие вопросы по тегам