Упрощение списка JSON для уникальных элементов dict - PullRequest
0 голосов
/ 10 января 2012

Новичок в python (также может использовать php). Обыскивал различные сайты / SO .. и все еще имеет ментальный блок.

Получил JSON, и пытаясь выяснить, как взять список, содержащий слова, и создать результирующий список, который имеет уникальный набор слов ...

В качестве примера, следующеесписок тестов:

[{"pStart1a": {"termVal":"1122","termMenu":"CLASS_SRCH_WRK2_STRM","instVal":"OSUSI",
"instMenu":"CLASS_SRCH_WRK2_INSTITUTION","goBtn":"CLASS_SRCH_WRK2_SSR_PB_SRCH",
"pagechk":"CLASS_SRCH_WRK2_SSR_PB_SRCH","nPage":"CLASS_SRCH_WRK2_SSR_PB_CLASS_SRCH"},
"pSearch1a":  
{"chk":"CLASS_SRCH_WRK2_MON","srchbtn":"DERIVED_CLSRCH_SSR_EXPAND_COLLAPS"}},
 {"pStart1":""},
 {"pStart1a":{"termVal":"1122","termMenu":"CLASS_SRCH_WRK2_STRM","instVal":"OSUSI",
 "instMenu":"CLASS_SRCH_WRK2_INSTITUTION","goBtn":"CLASS_SRCH_WRK2_SSR_PB_SRCH",
 "pagechk":"CLASS_SRCH_WRK2_SSR_PB_SRCH","nPage":"CLASS_SRCH_WRK2_SSR_PB_CLASS_SRCH"},
 "pSearch1a":
 {"chk":"CLASS_SRCH_WRK2_MON","srchbtn":"DERIVED_CLSRCH_SSR_EXPAND_COLLAPS"}},
 {"pStart1":""}]

Попытка получить следующий список уникальных диктовок, чтобы не было дублирующихся диктов.

[
  {"pStart1a": 
  {"termVal":"1122","termMenu":"CLASS_SRCH_WRK2_STRM","instVal":"OSUSI",
   "instMenu":"CLASS_SRCH_WRK2_INSTITUTION","goBtn":"CLASS_SRCH_WRK2_SSR_PB_SRCH",
   pagechk":"CLASS_SRCH_WRK2_SSR_PB_SRCH","nPage":"CLASS_SRCH_WRK2_SSR_PB_CLASS_SRCH"},
  "pSearch1a":
  {"chk":"CLASS_SRCH_WRK2_MON","srchbtn":"DERIVED_CLSRCH_SSR_EXPAND_COLLAPS"}},
  {"pStart1":""}]

Я рассматривал возможность итерации по первоначальному спискукопирование каждого диктанта в новый список и базовое сравнение, добавление следующего диктанта, если его нет в новом списке ... есть ли другой / лучший способ?

спасибо

Ответы [ 3 ]

3 голосов
/ 10 января 2012

Если oldlist содержит список диктов в Python (например, в результате json.loads (jsonstring)), то новый список может быть построен примерно так:

encountered = set()
newlist = []
for i in oldlist:
    repr_i = repr(i)
    if repr_i in encountered:
       continue
    encountered.add(repr_i)
    newlist.append(i)

print newlist

Вместо repr можно использовать другую функцию, например, хэш-дайджест repr.

0 голосов
/ 10 января 2012

Самый простой подход - использование list(set(your_list_of_dicts)) не сработает, потому что словари Python изменчивы и не могут хэшироваться (то есть они не реализуют __hash__).Это потому, что Python не может гарантировать, что хэш словаря не изменится после того, как вы вставите его в set или dict.

Однако, в вашем случае, так как вы (некажется, что) изменяя данные вообще, вы можете вычислить свой собственный хэш и использовать его вместе со словарем для сравнительно простого поиска уникальных объектов JSON без необходимости полного рекурсивного сравнения каждого словаря с другими.

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

def dict_hash(d):
    out = hashlib.md5()
    for key, value in d.iteritems():
        out.update(unicode(key))
        out.update(unicode(value))
    return out.hexdigest()

(Обратите внимание, что для каждого из них используется unicode(...)из ваших значений, возвращающих что-то уникальное - если у вас есть пользовательские классы в словарях, чей __unicode__ возвращает что-то вроде «экземпляра MyClass», это не удастся или потребует изменения. Кроме того, в вашем примере ваши словари плоские, нооставим читателю в качестве упражнения расширение этого решения для работы со словарями, содержащими другие диктанты или списки.)

Поскольку dict_hash возвращает строку, которая является неизменной, теперь вы можете использовать словарьнайти уникальные элементы:

uniques_map = {}
for d in list_of_dicts:
    uniques[dict_hash(d)] = d
unique_dicts = uniques_map.values()
0 голосов
/ 10 января 2012

Если я правильно понял ваш вопрос, вы можете попробовать это:

import json
from pprint import pprint

json_string = """[{"pStart1a": {"termVal":"1122","termMenu":"CLASS_SRCH_WRK2_STRM","instVal":"OSUSI",
"instMenu":"CLASS_SRCH_WRK2_INSTITUTION","goBtn":"CLASS_SRCH_WRK2_SSR_PB_SRCH",
"pagechk":"CLASS_SRCH_WRK2_SSR_PB_SRCH","nPage":"CLASS_SRCH_WRK2_SSR_PB_CLASS_SRCH"},
"pSearch1a":
{"chk":"CLASS_SRCH_WRK2_MON","srchbtn":"DERIVED_CLSRCH_SSR_EXPAND_COLLAPS"}},
 {"pStart1":""},
 {"pStart1a":{"termVal":"1122","termMenu":"CLASS_SRCH_WRK2_STRM","instVal":"OSUSI",
 "instMenu":"CLASS_SRCH_WRK2_INSTITUTION","goBtn":"CLASS_SRCH_WRK2_SSR_PB_SRCH",
 "pagechk":"CLASS_SRCH_WRK2_SSR_PB_SRCH","nPage":"CLASS_SRCH_WRK2_SSR_PB_CLASS_SRCH"},
 "pSearch1a":
 {"chk":"CLASS_SRCH_WRK2_MON","srchbtn":"DERIVED_CLSRCH_SSR_EXPAND_COLLAPS"}},
 {"pStart1":""}]
"""

result = {}
for dct in json.loads(json_string):
    for key, value in dct.iteritems():
        result[key] = value

pprint(result)

Выход:

 {u'pSearch1a': {u'chk': u'CLASS_SRCH_WRK2_MON',
                u'srchbtn': u'DERIVED_CLSRCH_SSR_EXPAND_COLLAPS'},
 u'pStart1': '',
 u'pStart1a': {u'goBtn': u'CLASS_SRCH_WRK2_SSR_PB_SRCH',
               u'instMenu': u'CLASS_SRCH_WRK2_INSTITUTION',
               u'instVal': u'OSUSI',
               u'nPage': u'CLASS_SRCH_WRK2_SSR_PB_CLASS_SRCH',
               u'pagechk': u'CLASS_SRCH_WRK2_SSR_PB_SRCH',
               u'termMenu': u'CLASS_SRCH_WRK2_STRM',
               u'termVal': u'1122'}}

EDIT

Обратите внимание, он преобразует ваш список диктов в диктовку. Может быть, будет легче делать дальнейшие операции над ним.

Также возможно преобразовать result в список:

list_result = [{key:value} for key, value in result.iteritems()]

ПРИМЕЧАНИЕ 2

Сравнение основано на ключах dict и извлекает вложенные значения на корневой уровень. Не знаю, доступно ли это для OP. Возможно, вы не должны использовать это решение. В любом случае это (в 8 раз) быстрее (по этим данным), чем repr() для сравнения диктов.

...