2016-02-21 5 views
4

У меня есть два списка, то первые из них содержит имена народов, с каждым человеком, связанным с различными символами, например, цифры, буквы, например:Сортировать и фильтровать список на основе элементов из второго списка

listNameAge = ['alain_90xx', 'fred_10y', 'george_50', 'julia_10l','alain_10_aa', 'fred_90', 'julia_50', 'george_10s', 'alain_50', 'fred_50', 'julia_90'] 

второй содержит имя лица:

listName = ['fred', 'julia', 'alain', 'george'] 

Использование второго списка, я хотел бы присоединиться третий список к первому, таким образом, что каждое имя в первом списке связано с его позиции с индексом во втором, то есть:

thirdlist = [2, 0, 3, 1, 2, 0, 1, 3, 2, 0, 1] 

Имя и символы разделены знаком подчеркивания, но символ может быть любого типа. Я мог бы перебрать элементы из listNameAge, отделить имена лиц от остальных символов, используя строку .split('_'), найти ее имя и найти ее индекс в listName, используя второй цикл.

Мне было интересно, есть ли более простой способ сделать это, т. Е. Избегать использования цикла и использовать только список понятий?

+0

Обратите внимание, что список понимания (что я предполагаю, что вы имели в виду) по-прежнему включает в себя цикл. – jonrsharpe

+0

Привет, да, я имел в виду понимание списка. То, что я хотел бы избежать, это «для циклов» – gregory

+1

И всевозможные списки ** по-прежнему связаны с циклами **. Я бы порекомендовал вам использовать словарь '{name: index}', чтобы избежать плохой временной сложности ответов. – jonrsharpe

ответ

1

Вы можете взять каждый элемент в listNameAge, затем split на '_', получить первую часть раскола, а затем использовать index, чтобы найти его во втором списке.

>>> [listName.index(i.split('_')[0]) for i in listNameAge] 
[2, 0, 3, 1, 2, 0, 1, 3, 2, 0, 1] 
+0

Хей, спасибо, что отлично работал, и это совершенно ясно. Мои списки не так длинны, поэтому сложность времени на самом деле не проблема. , – gregory

2

Для конкретного вопроса я бы рекомендовал вам использовать цикл только для ясности. Однако, если вы должны использовать список понимание, вы можете сделать это по существу тот же путь:

thirdlist = [listName.index(x[:x.find('_')]) for x in listNameAge] 
1
thirdList = [listName.index(string.split("_")[0]) for string in listNameAge] 

Это список понимание состоит из listName.index(string.split("_")[0] где string определяется для каждого элемента в listNameAge. string.split("_")[0] - это строка от начала строки до первого подчеркивания, поэтому listName.index(string.split("_")[0] является первым вхождением в listName.

+0

Можете ли вы добавить какое-то объяснение? – Will

+0

@Will: Я добавил некоторые. Если что-то может быть потенциально неясным, сообщите мне. – zondo

+0

Удивительный, спасибо! (Это всплыло в очереди просмотра. Ответы только на код, как правило, автоматически помечены.) – Will

3

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

namePos = dict((name, i) for (i, name) in enumerate(listName)) 
>>> [namePos[n.split('_')[0]] for n in listNameAge] 
[2, 0, 3, 1, 2, 0, 1, 3, 2, 0, 1] 

The (ожидаемый) время работы это код Θ (m + n) где m - длина первого списка, а n длина другого.

2

Вы можете попробовать это, проверьте каждый раз, когда listNameAge появляется в listName:

for x in listNameAge: 
    for y in listName: 
     if y in x: 
      thirdList.append(listName.index(y)) 

результат:

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

Я настоятельно рекомендую использовать .index() поскольку его сложность O(n) и делает общую сложность этой операции O(mn), где m и n - это размеры списков.

Вот такой быстрый один лайнер с помощью генераторов:

map(lambda (x,y): y[x[:x.find('_')]],izip(listNameAge, repeat(dict(izip(listName, count()))))) 

Более читаемый вариант будет (как показал Ami):

nameMap = dict(izip(listName, xrange(len(listName)))) 
thirdList = map(lambda x: nameMap[x[:x.find('_')]],listNameAge) 
Смежные вопросы