Pergunta

He're um problema interessante que procura a solução mais Pythonic. Suponha que eu tenho uma lista de mapeamentos {'id': id, 'url': url}. Alguns ids na lista são duplicados, e eu quero criar uma nova lista, com todas as duplicatas removidas. Eu vim com a seguinte função:

def unique_mapping(map):
    d = {}
    for res in map:
        d[res['id']] = res['url']

    return [{'id': id, 'url': d[id]} for id in d]

Acho que é bastante eficiente. Mas há uma "mais Pythonic" maneira? Ou talvez uma maneira mais eficiente?

Foi útil?

Solução

O seu exemplo pode ser reescrita ligeiramente para construir o primeiro dicionário usando uma expressão gerador e para remover necessidade de construção de outros mapeamentos. Apenas reutilizar os antigos:

def unique_mapping(mappings):
    return dict((m['id'], m) for m in mappings).values()

Embora este saiu como um one-liner, eu ainda acho que é muito legível.

Há duas coisas que você tem que manter em mente quando usar a sua solução original e mina:

  • os itens não será sempre devolvido na mesma ordem em que foram originalmente
  • a entrada mais tarde irá substituir entradas anteriores com o mesmo id

Se você não se importa, então eu sugiro a solução acima. Em outro caso, esta ordem e trata preserva a função ids de primeira encontrou com prioridade:

def unique_mapping(mappings):
    addedIds = set()
    for m in mappings:
        mId = m['id']
        if mId not in addedIds:
            addedIds.add(mId)
            yield m

Você pode precisar chamá-lo com list(unique_mappings(mappings)) se você precisar de uma lista e não um gerador.

Outras dicas

Há um par de coisas que você poderia melhorar.

  • Você está realizando dois loops, um sobre o dict original, e depois novamente sobre o dict resultado. Você poderia construir seus resultados em uma etapa em seu lugar.

  • Você poderia mudar para usar um gerador, para evitar a construção de toda a lista up-front. (Use lista (unique_mapping (itens)) para converter para uma lista completa se você precisar dele)

  • Não há nenhuma necessidade de armazenar o valor quando apenas a verificação de duplicatas, você pode usar um conjunto vez.

  • Você está recriando um dicionário para cada elemento, em vez de retornar o original. Isto pode ser realmente necessário (por exemplo. Você está modificando-os, e não quer tocar no original), mas se não for, é mais eficiente usar os dicionários já criadas.

Aqui está uma implementação:

def unique_mapping(items):
    s = set()
    for res in items:
        if res['id'] not in s:
            yield res
            s.add(res['id'])

Eu acho que isso pode ser feito ainda mais simples. Dicionários não toleram chaves duplicadas. Faça a sua lista de mapeamentos em um dicionário de mapeamentos. Isto irá remover duplicatas.

>>> someListOfDicts= [
    {'url': 'http://a', 'id': 'a'}, 
    {'url': 'http://b', 'id': 'b'}, 
    {'url': 'http://c', 'id': 'a'}]

>>> dict( [(x['id'],x) for x in someListOfDicts ] ).values()

[{'url': 'http://c', 'id': 'a'}, {'url': 'http://b', 'id': 'b'}]
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top