#python #duplicate-removal #nested-lists
#python #дубликат-удаление #вложенные списки
Вопрос:
У меня есть список списков, который выглядит как:
c = [['470', '4189.0', 'asdfgw', 'fds'],
['470', '4189.0', 'qwer', 'fds'],
['470', '4189.0', 'qwer', 'dsfs fdv']
...]
c
имеет около 30 000 внутренних списков. Что я хотел бы сделать, так это устранить дубликаты на основе 4-го элемента в каждом внутреннем списке. Таким образом, приведенный выше список списков будет выглядеть следующим образом:
c = [['470', '4189.0', 'asdfgw', 'fds'],['470', '4189.0', 'qwer', 'dsfs fdv'] ...]
Вот что у меня есть до сих пор:
d = [] #list that will contain condensed c
d.append(c[0]) #append first element, so I can compare lists
for bact in c: #c is my list of lists with 30,000 interior list
for items in d:
if bact[3] != items[3]:
d.append(bact)
Я думаю, что это должно сработать, но оно просто запускается и запускается. Я позволил ему работать в течение 30 минут, а затем убил его. Я не думаю, что программа должна занимать так много времени, поэтому я предполагаю, что с моей логикой что-то не так.
У меня такое чувство, что создание совершенно нового списка списков довольно глупо. Любая помощь будет высоко оценена, и, пожалуйста, не стесняйтесь придираться, пока я учусь. Также, пожалуйста, исправьте мой словарь, если он неверен.
Комментарии:
1. Как вы узнаете, какой из дубликатов необходимо удалить?
2. Рассматривали ли вы отдельный
set
из четвертых элементов, уже имеющихся в выходных данных? Это значительно ускорит поиск членства.3. Вы правы. Думаю, в настоящее время мне не нужна другая информация. Можете ли вы напрямую создать «набор», или мне выполнить итерацию по моему списку списков, создав список, а затем вызвать функцию set?
4. @user3754225 вы можете
add
изменять набор по мере продвижения, не повторяйтеc
дважды!5. Вы должны проверить pandas. Если (как я предполагаю) это не будет последней табличной операцией, которую вы выполняете с этими данными, pandas будет очень хорошей инвестицией. И ваша операция в pandas просто
df.drop_duplicates('col_4')
Ответ №1:
Я бы сделал это так:
seen = set()
cond = [x for x in c if x[3] not in seen and not seen.add(x[3])]
Объяснение:
seen
это набор, который отслеживает уже встреченные четвертые элементы каждого подсписка. cond
это сжатый список. В случае x[3]
, если (где x
находится подсписок в c
) не находится в seen
, x
будет добавлен cond
и x[3]
будет добавлен seen
.
seen.add(x[3])
вернется None
, так not seen.add(x[3])
будет всегда True
, но эта часть будет оцениваться только в том случае, если x[3] not in seen
есть True
, поскольку Python использует оценку короткого замыкания. Если выполняется второе условие, оно всегда будет возвращаться True
и будет иметь побочный эффект добавления x[3]
seen
. Вот еще один пример того, что происходит ( print
возвращает None
и имеет «побочный эффект» печати чего-либо):
>>> False and not print('hi')
False
>>> True and not print('hi')
hi
True
Комментарии:
1. Я смущен «и не». это логический эквивалент если бла, то бла? или это что-то совсем другое?
2. @user3754225 Я немного расширил объяснение
Ответ №2:
Используйте pandas. Я предполагаю, что у вас также есть лучшие имена столбцов.
c = [['470', '4189.0', 'asdfgw', 'fds'],
['470', '4189.0', 'qwer', 'fds'],
['470', '4189.0', 'qwer', 'dsfs fdv']]
import pandas as pd
df = pd.DataFrame(c, columns=['col_1', 'col_2', 'col_3', 'col_4'])
df.drop_duplicates('col_4', inplace=True)
print df
col_1 col_2 col_3 col_4
0 470 4189.0 asdfgw fds
2 470 4189.0 qwer dsfs fdv
Ответ №3:
У вас есть существенный логический недостаток в вашем текущем коде:
for items in d:
if bact[3] != items[3]:
d.append(bact)
это добавляет bact
один d
раз для каждого элемента, d
который не совпадает. Для минимального исправления вам необходимо переключиться на:
for items in d:
if bact[3] == items[3]:
break
else:
d.append(bact)
добавить bact
один раз, если все элементы в d
не совпадают. Я подозреваю, что это будет означать, что ваш код выполняется в более разумное время.
Кроме того, одним из очевидных улучшений производительности (повышение скорости, хотя и за счет использования памяти) было бы сохранение set
четвертого элемента, который вы видели до сих пор. При поиске в наборе используются хэши, поэтому проверка членства (выделено) будет намного быстрее.
d = []
seen = set()
for bact in c:
if bact[3] not in seen: # membership test
seen.add(bact[3])
d.append(bact)