题目
sql建表语句:
Create table If Not Exists Logs (log_id int);
Truncate table Logs;
insert into Logs (log_id) values ('1');
insert into Logs (log_id) values ('2');
insert into Logs (log_id) values ('3');
insert into Logs (log_id) values ('7');
insert into Logs (log_id) values ('8');
insert into Logs (log_id) values ('10');
分析:根据题目,我们可以先按照数字进行排序,然后求出差值来比较,如果差值相同,就证明这几个数字连续,然后按照差值进行分组,找出每个分组中的最大值和最小值来作为结束和开始的数字,这里的排序要用窗口函数中的row_number()来进行排序,图表分析如下:
sql实现:
with t1 as (
select log_id,row_number() over (order by log_id) rn from Logs -- 按照大小排序
),
t2 as (
select log_id,rn,log_id-rn rn2 from t1 -- 算出差值
)
select distinct min(log_id) over(partition by rn2) start_id,max(log_id) over(partition by rn2) end_id from t2 -- 按照差值分组,取出最小值和最大值作为开始数字和结束数字,然后去重
pandas分析和sql分析基本上一样
pandas实现:
import pandas as pd
def find_continuous_ranges(logs: pd.DataFrame) -> pd.DataFrame:
logs['rn']=logs['log_id'].rank(ascending=True) -- 排序
logs['rn2']=logs['log_id']-logs['rn'] -- 算出差值
logs['start_id']=logs.groupby(['rn2'])['log_id'].transform('min') -- 算出最小值
logs['end_id']=logs.groupby(['rn2'])['log_id'].transform('max')-- 算出最大值
logs=logs[['start_id','end_id']].drop_duplicates() -- 然后去重
return logs
说明一下这里使用transform('min')而不使用min(),是因为前者更像咱们sql中的窗口函数,而后者会出现一个小bug,当全部都是不连续的时候就会返回空值,因此这里使用transform('min')。