Переназначить значения словаря
у меня есть словарь, как
{'A': 0, 'B': 1, 'C': 2, 'D': 3, etc}
Как удалить элементы из этого словаря без создания пробелов в значениях, если словарь не упорядочен?
пример:
у меня есть большая матрица, где строки представляют слова, а столбцы представляют документы, где эти слова встречаются. Я храню слова и соответствующие им индексы как словарь. Е. Г. для этой матрицы
2 0 0
1 0 3
0 5 1
4 1 2
в словарь будет выглядеть так:
words = {'apple': 0, 'orange': 1, 'banana': 2, 'pear': 3}
если я удалю слова 'apple'
и 'banana'
матрица будет содержать всего две строки. Так что значение 'orange'
в словаре должно теперь равняться 0
, а не 1
и значение 'pear'
должно быть 1
вместо 3
.
в Python 3.6+ словари упорядочены, поэтому я могу просто написать что-то вроде этого, чтобы переназначить значения:
i = 0
for k, v in words.items():
v = i
i += 1
или, в качестве альтернативы
words = dict(zip(terms.keys(), range(0, matrix.shape[0])))
Я думаю, это далеко не самый эффективный способ изменить значения, и он не будет работать с неупорядоченными словари. Как это сделать эффективно? Есть ли способ легко переназначить значения в случае, если словарь не упорядочен?
5 ответов
включите дикт в отсортированном списке, а затем построить новый дикт без слов, которые вы хотите удалить:
import itertools
to_remove = {'apple', 'banana'}
# Step 1: sort the words
ordered_words = [None] * len(words)
for word, index in words.items():
ordered_words[index] = word
# ordered_words: ['apple', 'orange', 'banana', 'pear']
# Step 2: Remove unwanted words and create a new dict
counter = itertools.count()
words = {word: next(counter) for word in ordered_words if word not in to_remove}
# result: {'orange': 0, 'pear': 1}
это имеет время выполнения O (n), потому что ручное упорядочение списка с операциями индексирования является линейной операцией, в отличие от sorted
который будет O (N log n).
см. также документацию для itertools.count
и next
.
вы можете использовать существующую логику, используя представление сортируемого словаря:
import operator
words = {'apple': 0, 'orange': 1, 'banana': 2, 'pear': 3}
sorted_words = sorted(words.items(), key=operator.itemgetter(1))
for i, (k, v) in enumerate(sorted_words):
words[k] = i
изначально у нас есть
words = {'apple': 0, 'orange': 1, 'banana': 2, 'pear': 3}
чтобы изменить порядок на основе от минимального до максимального, вы можете использовать sorted
и понимание словаря.
std = sorted(words, key=lambda x: words[x])
newwords = { word : std.index(word) for word in std }
это хорошо..?
вы всегда можете сохранить перевернутый словарь, который отображает индексы в слова, и использовать его в качестве ссылки для сохранения порядка исходного словаря. Затем вы можете удалить слова и снова перестроить словарь:
words = {'apple': 0, 'orange': 1, 'banana': 2, 'pear': 3}
# reverse dict for index -> word mappings
inverted = {i: word for word, i in words.items()}
remove = {'apple', 'banana'}
# sort/remove the words
new_words = [inverted[i] for i in range(len(inverted)) if inverted[i] not in remove]
# rebuild new dictionary
new_dict = {word: i for i, word in enumerate(new_words)}
print(new_dict)
Выходы:
{'orange': 0, 'pear': 1}
Примечание: как и принятый ответ, это также O(n)
.
вы используете неправильный инструмент (dict
) для задания вы должны использовать list
class vocabulary:
def __init__(self, *words):
self.words=list(words)
def __getitem__(self, key):
try:
return self.words.index(key)
except ValueError:
print (key + " is not in vocabulary")
def remove(self, word):
if type(word)==int:
del self.words[word]
return
return self.remove(self[word])
words = vocabulary("apple" ,"banana", "orange")
print (words["banana"]) # outputs 1
words.remove("apple")
print (words["banana"]) # outputs 0
примечание по сложности
у меня было несколько комментариев, упоминая, что dict
более эффективно, потому что это время поиска O(1)
и время поиска list
и O(n)
.
это просто не так в этом случае.
на O(1)
гарантия хэш-таблицей (dict
в python), является результатом амортизированного сложность, означающая, что вы усредняете общее использование таблицы поиска, которая является генерируется один раз, предполагая, что ваша хэш-функция сбалансирована.
этот амортизированный расчет не учитывает удаление всего словаря и его регенерацию каждый раз, когда вы удаляете элемент, как предлагают некоторые другие ответы.
на list
реализация и dict
реализация имеет ту же наихудшую сложность O(n)
.
тем не менее,list
реализация может быть оптимизирована с помощью двух строк python (bisect
) в худшем случае сложность O(log(n))