LeetCode数据专题:1795. 每个产品在不同商店的价格

30 阅读2分钟

LeetCode数据专题:1795. 每个产品在不同商店的价格

题目描述

表:Products

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| product_id  | int     |
| store1      | int     |
| store2      | int     |
| store3      | int     |
+-------------+---------+SQL 中,这张表的主键是 product_id(产品Id)。
每行存储了这一产品在不同商店 store1, store2, store3 的价格。
如果这一产品在商店里没有出售,则值将为 null

请你重构 Products 表,查询每个产品在不同商店的价格,使得输出的格式变为(product_id, store, price) 。如果这一产品在商店里没有出售,则不输出这一行。

输出结果表中的 顺序不作要求 。

查询输出格式请参考下面示例。

示例 1:

输入:
Products table:
+------------+--------+--------+--------+
| product_id | store1 | store2 | store3 |
+------------+--------+--------+--------+
| 0          | 95     | 100    | 105    |
| 1          | 70     | null   | 80     |
+------------+--------+--------+--------+
输出:
+------------+--------+-------+
| product_id | store  | price |
+------------+--------+-------+
| 0          | store1 | 95    |
| 0          | store2 | 100   |
| 0          | store3 | 105   |
| 1          | store1 | 70    |
| 1          | store3 | 80    |
+------------+--------+-------+
解释:
产品 0 在 store1、store2、store3 的价格分别为 95100105。
产品 1 在 store1、store3 的价格分别为 7080。在 store2 无法买到。

解题思路

我们可以使用动态的交叉连接(CROSS JOIN)来获取不同商店的组合。然后,使用条件语句和聚合函数来计算每个产品在不同商店的价格。

代码实现

MySQL 实现

  • union
SELECT product_id, 'store1' AS store, store1 AS price 
FROM Products 
WHERE store1 IS NOT NULL

UNION 
SELECT product_id, 'store2' AS store, store2 AS price 
FROM Products 
WHERE store2 IS NOT NULL

UNION 
SELECT product_id, 'store3' AS store, store3 AS price 
FROM Products 
WHERE store3 IS NOT NULL

Pandas 实现

  • union
def rearrange_products_table(products: pd. DataFrame ) -> pd. DataFrame : 
    a = products.loc[products['store1'].notna(), ['product_id', 'store1']]
    a['store'] = "store1"
    a.rename(columns={'store1':'price'}, inplace=True)
    a = a[['product_id', 'store', 'price']]

    b = products.loc[products['store2'].notna(), ['product_id', 'store2']]
    b['store'] = "store2"
    b.rename(columns={'store2':'price'}, inplace=True)
    b = b[['product_id', 'store', 'price']]
    
    c = products.loc[products['store3'].notna(), ['product_id', 'store3']]
    c['store'] = "store3"
    c.rename(columns={'store3':'price'}, inplace=True)
    c = c[['product_id', 'store', 'price']]
      
    answer = pd.concat([a, b, c])
    return answer
  • 透视
import pandas as pd

def rearrange_products_table(products: pd. DataFrame ) -> pd. DataFrame : 
    df = products.melt(
        id_vars='product_id', 
        value_vars=['store1', 'store2', 'store3'],
        var_name='store', 
        value_name='price')
    df = df.dropna(axis=0)
    return df
)
  • 行列转换stack
import pandas as pd

def rearrange_products_table(products: pd.DataFrame) -> pd.DataFrame:

    # set_index 会按照[product_id]进行分行(大行包小行)
    df = products.set_index(['product_id']).stack()

    # 与 set_index 对照看
    df = df.reset_index()

    # 重新命名
    df.columns = ['product_id','store','price']

    return df
  • 已知输入:
| product_id | store1 | store2 | store3 |
| ---------- | ------ | ------ | ------ |
| 0          | 95     | 100    | 105    |
| 1          | 70     | null   | 80     |
  • 三次df的输出为:
product_id        
0           store1     95
            store2    100
            store3    105
1           store1     70
            store3     80
dtype: Int64

   product_id level_1    0
0           0  store1   95
1           0  store2  100
2           0  store3  105
3           1  store1   70
4           1  store3   80

| product_id | store  | price |
| ---------- | ------ | ----- |
| 0          | store1 | 95    |
| 0          | store2 | 100   |
| 0          | store3 | 105   |
| 1          | store1 | 70    |
| 1          | store3 | 80    |