Python: перечислить список строковых «ключей» в целые числа

Я искал некоторое время, но не нашел ничего, что точно объясняло бы, что я пытаюсь сделать.

В основном у меня есть список строковых «меток», например. ["коричневый", "черный", "синий", "коричневый", "коричневый", "черный"] и т. д. Я хочу преобразовать это в список целых чисел, где каждая метка соответствует целому числу, поэтому

["brown", "black", "blue", "brown", "brown", "black"]

становится

[1, 2, 3, 1, 1, 2]

Я изучил функцию перечисления, но когда я дал ей свой список строк (который довольно длинный), он присвоил целое число каждой отдельной метке вместо того, чтобы присвоить одной и той же метке одно и то же целое число:

[(1,"brown"),(2,"black"),(3,"blue"),(4,"brown"),(5,"brown"),(6,"black")]

Я знаю, как я мог бы сделать это с помощью длинного и громоздкого цикла for и проверок if-else, но мне действительно любопытно, есть ли более элегантный способ сделать это всего одной или двумя строками.


person gpanders    schedule 17.06.2013    source источник


Ответы (4)


У вас есть неуникальные ярлыки; вы можете использовать defaultdict для генерации чисел при первом доступе в сочетании со счетчиком:

from collections import defaultdict
from itertools import count
from functools import partial

label_to_number = defaultdict(partial(next, count(1)))
[(label_to_number[label], label) for label in labels]

Это генерирует счетчик в порядке первого появления меток в labels.

Демо:

>>> labels = ["brown", "black", "blue", "brown", "brown", "black"]
>>> label_to_number = defaultdict(partial(next, count(1)))
>>> [(label_to_number[label], label) for label in labels]
[(1, 'brown'), (2, 'black'), (3, 'blue'), (1, 'brown'), (1, 'brown'), (2, 'black')]

Поскольку мы используем словарь, поиск по номерам требует постоянной стоимости, поэтому вся операция займет линейное время в зависимости от длины списка labels.

В качестве альтернативы используйте set() для получения уникальных значений, а затем сопоставьте их с количеством enumerate():

label_to_number = {label: i for i, label in enumerate(set(labels), 1)}
[(label_to_number[label], label) for label in labels]

Это присваивает номера более произвольно, так как set() объекты не упорядочены:

>>> label_to_number = {label: i for i, label in enumerate(set(labels), 1)}
>>> [(label_to_number[label], label) for label in labels]
[(2, 'brown'), (3, 'black'), (1, 'blue'), (2, 'brown'), (2, 'brown'), (3, 'black')]

Однако для этого требуется дважды пройти через labels.

Ни один из подходов не требует от вас сначала определить словарь меток; сопоставление создается автоматически.

person Martijn Pieters    schedule 17.06.2013

Сначала вы можете создать словарь, например:

dict = {"brown":1 , "black": 2, "blue": 3 }

А потом:

li = ["brown", "black", "blue", "brown", "brown", "black"]
[dict[i] for i in li]
person Ankur Ankan    schedule 17.06.2013

Попробуй это:

lst = ["brown", "black", "blue", "brown", "brown", "black"]
d = {"brown":1, "black":2, "blue":3}

[d[k] for k in lst]
=> [1, 2, 3, 1, 1, 2]

Конечно, чтобы это работало, вы должны где-то определить эквивалентности — выше я использовал для этого словарь. В противном случае невозможно узнать, соответствует ли коричневый цвет цифре 1 и т. д.

person Óscar López    schedule 17.06.2013

Самый простой фрагмент кода, который воспроизводит запрошенный вами ответ:

l = ["brown", "black", "blue", "brown", "brown", "black"]
i = [l.index(x)+1 for x in l]
print i

>>> [1, 2, 3, 1, 1, 2]

Для длинного списка это может быть довольно медленным, но он генерирует именно то, что вы просили, без какой-либо подготовки.

person Simon Callan    schedule 17.06.2013
comment
Если список меток большой, это будет ужасно плохо работать, так как .index() должен сканировать список для каждой итерации цикла. - person Martijn Pieters; 17.06.2013
comment
Это то, о чем я говорил, когда я сказал, что это может быть медленным для длинного списка, но это зависит от того, насколько велик список. - person Simon Callan; 17.06.2013
comment
Это также предполагает что-то неявное в вопросе о целочисленном назначении. Во втором примере, таком как l = ["brown", "black", "brown", "blue", "brown", "black"], для синего цвета будет присвоено значение 4, тогда как в словарном подходе для синего цвета будет присвоено значение 3 в обоих случаях. - person dansalmo; 17.06.2013