如何在Python中基于id合并3个列表?

2024-06-08 11:33:38 发布

您现在位置:Python中文网/ 问答频道 /正文

我有三个类似的列表:

productData = [
  {
    'productId': 1000,
    'productName': 'Product 1000'
  },
  {
    'productId': 1001,
    'productName': 'Product 1001'
  }
]
stockData = [
  {
    'productId': 1000,
    'locationId': 1,
    'stock': 21
  },
  {
    'productId': 1000,
    'locationId': 2,
    'stock': 8
  },
  {
    'productId': 1001,
    'locationId': 1,
    'stock': 4
  },
  {
    'productId': 1001,
    'locationId': 2,
    'stock': 10
  }
]

locationData = [
  {
    'locationId': 1,
    'locationName': 'Location 1'
  },
  {
    'locationId': 2,
    'locationName': 'Location 2'
  }
]

我想根据productId和locationId合并它,所以它将如下所示:

result = [
  {
    productName: 'Product 1000',
    stock: {
      total: 29,
      detail: [
        {
          locationName: 'Location 1',
          stock: 21
        },
        {
          locationName: 'Location 2',
          stock: 8
        }
      ]
    }
  },
  {
    productName: 'Product 1001',
    stock: {
      total: 14,
      detail: [
        {
          locationName: 'Location 1',
          stock: 4
        },
        {
          locationName: 'Location 2',
          stock: 10
        }
      ]
    }
  }
]

我用ChainMap做了一些代码,但结果不是我所需要的, 以下是我的代码的结果:

[{'locationId': 1, 'locationName': 'Location 1', 'productId': 1000, 'stock': 21, 'productName': 'Product 1000'}, {'locationId': 2, 'locationName': 'Location 2'}]

首先我将productData和具有productId的stockData分组,然后根据结果将其与具有locationId的locationData分组,但结果是错误的, 你能告诉我我的密码有什么问题吗

grouped_subdicts = groupby(sorted(productData + stockData, key=itemgetter("productId")), itemgetter("productId"))

result = [dict(ChainMap(*g)) for k, g in grouped_subdicts]

grouped_subdicts_2 = groupby(sorted(result + locationData, key=itemgetter("locationId")), itemgetter("locationId"))
result_2 = [dict(ChainMap(*g)) for k, g in grouped_subdicts_2]

print(result_2)

Tags: stocklocationresultproductgroupedchainmapproductiditemgetter
2条回答

与groupby不同,我使用了一种更简单的解决方案,只涉及dictlist,因此您可以更好地控制您的上下文:

def make_product_entities(product_data):
    product_entities = {}
    for product in product_data:
        product_entities[product["productId"]] = {
            "productName": product["productName"],
            "stock": {"total": 0, "detail": []},
        }
    return product_entities


def make_location_entities(location_data):
    location_entities = {}
    for location in location_data:
        location_entities[location["locationId"]] = {
            "locationName": location["locationName"]
        }
    return location_entities


def accumulate_product_data(product_data, stock_data, location_data):

    product_entities = make_product_entities(product_data)
    location_entities = make_location_entities(location_data)

    for stock in stock_data:
        product_entity = product_entities[stock["productId"]]
        location_entity = location_entities[stock["locationId"]]

        product_entity["stock"]["total"] += stock["stock"]
        product_entity["stock"]["detail"].append(
            {"locationName": location_entity["locationName"], "stock": stock["stock"]}
        )

    return list(product_entities.values())

我使用make_product_entitiesmake_location_entities为产品和位置数据创建查找字典

然后在accumulate_product_data中,我创建了那些查找字典,然后由于stock_data是位置和产品之间的关联,我通过库存循环,对产品实体进行变异,然后在累积结束时,我只返回来自product_entities字典的值

试试看它是否适合你的问题

我会将所有三个列表转换为数据帧,然后使用groupbypd.to_json获得最终结果

df_product = pd.DataFrame(productData,columns=['productId', 'productName'])
df_stock = pd.DataFrame(stockData,columns=['productId', 'locationId', 'stock'])
df_location = pd.DataFrame(locationData,columns=['locationId', 'locationName'])

合并所有这些dfs以形成一个完整的数据框架,使用groupbytransform

df_merged_three_lists = df_stock.merge(df_product).merge(df_location)
df_merged_three_lists["total"] = df_merged_three_lists.groupby("productName", as_index=False)["stock"].transform('sum')

如下所示:

    productId   locationId  stock   productName     locationName    total
0   1000        1           21      Product 1000    Location 1      29
1   1000        2           8       Product 1000    Location 2      29
2   1001        1           4       Product 1001    Location 1      14
3   1001        2           10      Product 1001    Location 2      14

然后使用groupby来获得最终结果

df_build_detail = df_merged_three_lists.groupby(["productName", "total"])[["locationName", "stock"]].apply(
lambda x: x.to_dict("records")).reset_index(name="detail")

result = df_build_detail.to_json(orient="records", force_ascii=False)

结果:

[{"productName":"Product 1000","total":29,"detail":[{"locationName":"Location 1","stock":21},{"locationName":"Location 2","stock":8}]},{"productName":"Product 1001","total":14,"detail":[{"locationName":"Location 1","stock":4},{"locationName":"Location 2","stock":10}]}]

相关问题 更多 >