Как совместить эти два списка? - PullRequest
0 голосов
/ 24 июня 2019

Есть два списка:


l1 = [
{"name":"name_1", "id":"1231"},
...,
{"name":"name_10000", "id":"13113"},
...
]


# list of class A's instance
l2 =[
<__main__.A object at 0x000001F23FDFCE10>,
<__main__.A object at 0x000001F23FDFCEB8>,
...
<__main__.A object at 0x000001F23FDFCEB8>,
]



# For example
class A:
    def __init__(self, id, status):
        self.id = id
        self.status = status

l2 = [
    A(item, "status_{}".format(item)) for item in range(1, 10000)
]

Я хочу объединить эти два списка на основе l1 и создать новый список, например:

l3 = [

{"id": "2313", "name":"name_2313", "status":"status_2313"},
...

{"id": "xxx", "name":"name_xxx", "status":"status_xxx"},

# if there's no match in l2, then the result should be 
{"id": "xxx", "name":"name_xxx", "status": None},

]

Я попытался с использованием списка, как показано ниже:


l3 = [
        {
            "id": item["id"],
            "name": item["name"],
            "status": stat.status if stat.id == item['id'] else None,

        }
    for item in l1 for stat in l2
 ]

Но на увеличение количества списков уйдет много времени, как я могу объединить эти списки наиболее эффективным способом?

Ответы [ 2 ]

2 голосов
/ 25 июня 2019

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

То есть вместо списка l2 используйте

l2 = {item: A(item, "status_{}".format(item)) for item in ("1231", "13113")}

(в качестве примера я использую только два элемента)

Теперь у вас есть предмет: пара экземпляров

{'1231': <__main__.A object at 0x10a8b6470>, '13113': <__main__.A object at 0x10a8b65c0>}

после этого l3 будет только один цикл.

>>> l1 = [
... {"name":"name_1", "id":"1231"},
... {"name":"name_10000", "id":"13113"}
... ]
>>> l3 = [{**i, "status": l2.get(i["id"]).status} for i in l1]
>>> l3
[{'name': 'name_1', 'id': '1231', 'status': 'status_1231'}, {'name': 'name_10000', 'id': '13113', 'status': 'status_13113'}]

мы все еще сталкиваемся с одной проблемой. Что если у l2 нет этого идентификатора? для этого мы можем создать фиктивный класс со статусом, который возвращает None

>>> class Dummy:
...     def __init__(self):
...         self.status = None
... 
>>> l1 = [
... {"name":"name_1", "id":"12"},
... {"name":"name_10000", "id":"13113"}
... ]
>>> 
>>> l2 = {item: A(item, "status_{}".format(item)) for item in ("1231", "13113")}
>>> 
>>> l3 = [{**i, "status": l2.get(i["id"], Dummy()).status} for i in l1]
>>> l3
[{'name': 'name_1', 'id': '12', 'status': None}, {'name': 'name_10000', 'id': '13113', 'status': 'status_13113'}]

смотрите здесь, мы используем get, потому что get возвращает второе значение аргумента, если первый аргумент отсутствует.

бонус.

если вы получаете данные о l2 откуда-то, то вы можете сделать один цикл, чтобы преобразовать l2 в словарь, как я показал, и затем выполнить то же самое. таким образом вы делаете только два отдельных цикла вместо вложенного цикла.

дайте мне знать, если после этого у вас возникнут проблемы.

1 голос
/ 25 июня 2019

Предположение: вы хотите, чтобы новый список диктов из l1 обновлялся со статусами от объектов в l2.

Учитывая

Класс.Для удобства мы используем простой класс данных:

import dataclasses as dc


@dc.dataclass
class A:
    id_: int
    status: str

Более простой список диктов:

lst1 = [
    {"name":"name_0", "id_":0},
    {"name":"name_1", "id_":1},
    {"name":"name_2", "id_":2},
    {"name":"name_3", "id_":3},
]

Сокращенный список A объектов:

lst2 = [A(i, f"status_{i}") for i in range(3)]
lst2
# [A(id_=0, status='status_0'),
#  A(id_=1, status='status_1'),
#  A(id_=2, status='status_2')]

Код

Сделайте запрос поиска для уменьшения зацикливания.Здесь мы сопоставляем идентификатор со статусом из объектов в lst2:

lookup = {a.id_: a.status  for a in lst2}
lookup
# {0: 'status_0', 1: 'status_1', 2: 'status_2'}

Слияние диктов со значением поиска:

[{**d, **dict(status=lookup.get(d["id_"], None))} for d in lst1]
#[{'name': 'name_0', 'id_': 0, 'status': 'status_0'},
# {'name': 'name_1', 'id_': 1, 'status': 'status_1'},
# {'name': 'name_2', 'id_': 2, 'status': 'status_2'},
# {'name': 'name_3', 'id_': 3, 'status': None}]

Примечания

  • Классы данных имеют чистые повторы, но обычный класс может заменить класс данных.
  • Поскольку l можно спутать с 1, используется lst.
  • Similary, id - зарезервированное имя в Python;мы используем id_.
  • По умолчанию состояние равно None, если поиск не удается.
  • Этот подход предполагает "Есть два списка [с]:";в противном случае сделайте дикт вместо ответа lst2 (см. @Aish Sharma's).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...