Как получить словарь со значениями, которые являются списком, содержащим индексы каждого ключа

Мой код:

def collect_ind(source):
    keys = []
    indexes = []
    for x in source:
        keys.append(x)
    i = 0
    while i < len(source):
        indexes.append([i])
        i += 1
    print(keys, '=', indexes)
    # return keys, indexes
    dictionary = dict(zip(keys, indexes))
    print(dictionary)
    return dictionary  # {'g': [0], 'o': [2]}


collect_ind('goo')

Как сделать так, чтобы функция возвращала словарь, в котором будут индексы каждого встретившегося ключа? Сейчас моя функция возвращает {'g': [0], 'o': [2]}, а должно быть: {'g': [0], 'o': [1, 2]}, ведь 'o' - встречается 2 раза в списке. Помогите пожалуйста! Я новичок в Python.


Ответы (3 шт):

Автор решения: n1tr0xs

Вот так:

def collect_ind(src):
    dictionary = dict()
    for i in range(len(src)):
        key = src[i]
        try:
            dictionary[key].append(i)
        except KeyError:
            dictionary[key] = [i]
    return dictionary
    
collect_ind('goo')

Можно сделать вспомогательную функцию (однако этот вариант сильно дольше):

def find_all(src, el):
    return [i for i in range(len(src)) if src[i] == el]

def collect_ind(src):
    dictionary = {key: find_all(src, key) for key in src}
    return dictionary

Второй вариант, но find_all быстрее:

def find_all(src, el):
    result = []
    offset = -1
    while True:
        try:
            offset = src.index(el, offset+1)
        except ValueError:
            return result
        result.append(offset)

def collect_ind(src):
    dictionary = {key: find_all(src, key) for key in src}
    return dictionary
→ Ссылка
Автор решения: CrazyElf

Довольно же просто решается прямо "в лоб" с использованием enumerate (с помощью него можно получить пары индекс-значение для коллекции) и метода .get для словаря (позволяющего задать дефолтное значение для ключей, которых нет в словаре):

def collect_ind(src):
    d = {}
    for i,x in enumerate(src):
        d[x] = d.get(x, []) + [i]
    return d

print(collect_ind('goo'))

Вывод:

{'g': [0], 'o': [1, 2]}
→ Ссылка
Автор решения: SergFSM

а если списки заменить на таплы, то получится как-то так:

def collect_ind(source):
    d = dict.fromkeys(source,())
    for i,x in enumerate(source):
        d[x] += (i,)
    return d

collect_ind('google')

# {'g': (0, 3), 'o': (1, 2), 'l': (4,), 'e': (5,)}
→ Ссылка