Преобразуйте список в словарь, затем объедините несколько словарей в одно по значению ключа. - PullRequest
0 голосов
/ 17 октября 2019

У меня есть три списка Python, которые я хочу сделать в словаре, а затем соединить эти три словаря в один на основе значений ключа.

Мои списки Python сделаны так:

with open ('full_product_shipments.xml','r') as file2:
    full_product_shipments = list([line.strip().replace('{"','').replace('}','').replace('"','').replace(':',',').split(',') for line in file2])

И они выглядят так:

list1

[['transaction_id', '224847627', 'product_amount', '2.73', 'user_invoice_date', '2018-12-21'],
['transaction_id', '67919397', 'product_amount', '2.73', 'user_invoice_date', '2017-10-26']]

list2

[['tracking_code', '29285908', 'from_country', 'FR', 'to_country', 'FR', 'package_type_id', '10', 'transaction_id', '172238850', 'shipping_label_created', '2018-09-25 18', '40', '52'],
['tracking_code', '22105784', 'from_country', 'FR', 'to_country', 'FR', 'package_type_id', '10', 'transaction_id', '111423825', 'shipping_label_created', '2018-04-13 11', '22', '44']]

list3

[['tracking_code', '21703238', 'from_country', 'FR', 'to_country', 'FR', 'amount', '3.23'],
['tracking_code', '41545695', 'from_country', 'FR', 'to_country', 'FR', 'amount', '2.9']]

list1 и list2 оба имеютtransaction_id, к которому мне нужно будет присоединиться к ним, как только я преобразую их в диктовку.

Вновь объединенные списки ( list1 и list2 ) и list3 у обоих есть tracking_id, с помощью которых я хочу присоединиться к ним один раз list3 преобразуется в dict.

Я пытался использовать это:

result=[x.update(amount=y['amount']) for x in full_product_shipments for y in full_provider_invoices if x['transaction_id'] == y['transaction_id']]

Но это бросает мне ошибку типа:

TypeError: list indices must be integers or slices, not str

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

Ответы [ 3 ]

1 голос
/ 17 октября 2019

Было бы легче присоединиться, если исходные необработанные данные были в формате «json» вместо «xml». Если вы загружаете данные с помощью REST API, попробуйте ввести ключевое слово в конце '& $ format = json' и посмотреть, возвращается ли результат файла в виде строки json. Например, это будет работать в SAP REST API, но я думаю, что это стандартный параметр для многих поставщиков API.

Чтобы поделиться опытом, который у меня был на работе, мне дали API SAP, где ответом по умолчанию был XML ... Я пытался осмыслить его, используя библиотеки синтаксического анализа Python XML (бесконечно поражал мой мозг), пока не понял, чтоможет просто передать параметр в необработанную строку URL, и вместо этого он вернется в виде JSON. Исходя из моего опыта, это моя рекомендация для вашей проблемы.

Вот пример общедоступного API с синтаксисом… попробуйте поэкспериментировать с аналогичными комбинациями для вашего API.

https://vpic.nhtsa.dot.gov/api/

https://vpic.nhtsa.dot.gov/api/Home/Index/LanguageExamples

Теперь, если вы можете загрузить строку JSON, довольно легко преобразовать ее в словарь Python ... много ресурсов в Интернете, как это сделать. Тогда преобразование словаря Python в pandas dataframe очень просто, много ресурсов онлайн, как это сделать. Тогда объединить несколько фреймов данных очень просто, много ресурсов онлайн, как это сделать.

Если вы не можете получить строку JSON, есть несколько (более сложных) ресурсов онлайн о том, как конвертировать из XML в JSON. Вот несколько ссылок:

Как преобразовать строку XML в словарь?

https://ericscrivner.me/2015/07/python-tip-convert-xml-tree-to-a-dictionary/

http://code.activestate.com/recipes/573463-converting-xml-to-dictionary-and-back/

Вы обнаружите, что работать со словарем гораздо проще, чем со списком. Список предназначен для хранения упорядоченных элементов, но в вашем списке хранится несколько пар ключ-значение (именно для этого подходит словарь).

Надеюсь, это поможет!

1 голос
/ 17 октября 2019

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

l1 = [['transaction_id', '224847627', 'product_amount', '2.73', 'user_invoice_date', '2018-12-21'], ['transaction_id', '67919397', 'product_amount', '2.73', 'user_invoice_date', '2017-10-26']]
l2 = [['tracking_code', '29285908', 'from_country', 'FR', 'to_country', 'FR', 'package_type_id', '10', 'transaction_id', '172238850', 'shipping_label_created', '2018-09-25 18', '40', '52'], ['tracking_code', '22105784', 'from_country', 'FR', 'to_country', 'FR', 'package_type_id', '10', 'transaction_id', '111423825', 'shipping_label_created', '2018-04-13 11', '22', '44']]
l3 = [['tracking_code', '21703238', 'from_country', 'FR', 'to_country', 'FR', 'amount', '3.23'], ['tracking_code', '41545695', 'from_country', 'FR', 'to_country', 'FR', 'amount', '2.9']]

# Convert everything to dict
result = {y['transaction_id']:y for y in [dict(zip(x[::2], x[1::2])) for x in l1]}
d2 = {y['transaction_id']:y for y in [dict(zip(x[::2], x[1::2])) for x in l2]}
d3 = {y['tracking_code']:y for y in [dict(zip(x[::2], x[1::2])) for x in l3]}

# Update result dict with data from the other lists.
for entry in result.values():
    entry.update(d2[entry['transaction_id']])
    entry.update(d3[entry['tracking_code']])
0 голосов
/ 17 октября 2019

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

Если это невозможно, следующая программа будет работатьчерез ваши разные списки попробуйте получить идентификатор транзакции, который будет использоваться в качестве ключа для нашего основного defaultdict, который будет заполнен пустым dict, если идентификатор не существует, или добавьте новую запись в свой словарь в противном случае.

Вот полный код. Обратите внимание, что я изменил второй список, чтобы иметь идентификатор, соответствующий первому списку, чтобы показать, как поля из отдельных списков могут быть объединены в одном и том же тексте. Это предполагает отсутствие перекрытия между полями.

from collections import defaultdict

list1 = [['transaction_id', '224847627', 'product_amount', '2.73', 'user_invoice_date', '2018-12-21'],
['transaction_id', '67919397', 'product_amount', '2.73', 'user_invoice_date', '2017-10-26']]

# list2 = [['tracking_code', '29285908', 'from_country', 'FR', 'to_country', 'FR', 'package_type_id', '10', 'transaction_id', '172238850', 'shipping_label_created', '2018-09-25 18', '40', '52'],
list2 = [['tracking_code', '29285908', 'from_country', 'FR', 'to_country', 'FR', 'package_type_id', '10', 'transaction_id', '224847627', 'shipping_label_created', '2018-09-25 18', '40', '52'],
['tracking_code', '22105784', 'from_country', 'FR', 'to_country', 'FR', 'package_type_id', '10', 'transaction_id', '111423825', 'shipping_label_created', '2018-04-13 11', '22', '44']]

list3 = [['tracking_code', '21703238', 'from_country', 'FR', 'to_country', 'FR', 'amount', '3.23'],
['tracking_code', '41545695', 'from_country', 'FR', 'to_country', 'FR', 'amount', '2.9']]




def aggregate_lists(*lists):
    transactions = defaultdict(dict)

    for list in lists:
        for row in list:
            try:
                id_col = row.index('transaction_id')
                transaction_id = row[id_col + 1]
            except ValueError:
                continue # Better error handling to be added.

            for col in range(0, len(row), 2):
                if col != id_col:
                    transactions[transaction_id][row[col]] = row[col + 1]

    return transactions

def main():
    transactions = aggregate_lists(list1, list2, list3)
    for k, props in transactions.items():
        print(f'Transaction: {k}')
        for k, v in props.items():
            print(f'\t{k}: {v}')

if __name__ == '__main__':
    main()

Вот этот вывод:

Transaction: 224847627
    product_amount: 2.73
    user_invoice_date: 2018-12-21
    tracking_code: 29285908
    from_country: FR
    to_country: FR
    package_type_id: 10
    shipping_label_created: 2018-09-25 18
    40: 52
Transaction: 67919397
    product_amount: 2.73
    user_invoice_date: 2017-10-26
Transaction: 111423825
    tracking_code: 22105784
    from_country: FR
    to_country: FR
    package_type_id: 10
    shipping_label_created: 2018-04-13 11
    22: 44

Я только что понял, что list3 не имеет идентификатора транзакции, который поэтому игнорируется. В любом случае, это должно дать идею.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...