一.问题介绍
工作中遇到一个问题,一个列表中,存在多个以"-“连接的范围string,希望可以把规则集压缩,即融合的范围融合
I:[10-30kg,3-10kg,3-10kg,1-3kg,3-10kg,3-10kg,50-100kg]
O:[1-30kg,50-100kg]
注:范围string无序且有重复
二.python实现
①去重并排序
def takeFirst(elem):
return int(elem.split('-')[0])
input = list(set(input.split(","))) # 去重
input.sort(key=takeFirst) # 排序
'''此时input为[3-10kg,10-30kg,50-100kg]'''
②规则融合
def merge(elem1,elem2):
elem1 = elem1.split('-') # 将元素基于-分割,次数为没有后缀的情况,如果像我上面的实例有kg作为后缀,可以先对string将进行切片,如elem1[0:-2]
elem2 = elem2.split('-')
# 如果前一个元素的最大值等于后一个元素的最小值,则进行融合,返回融合值,否则返回空
if elem1[1] == elem2[0]:
return ''.join([elem1[0],'-',elem2[1]])
def mergelist(list):
res = []
# 如果此input列表只有一个元素,则返回原列表
if len(list) == 1:
return list
# 从列表后端遍历所有相邻元素对
a = len(list)-2
while a >= 0:
new_elem = merge(list[a],list[a+1])
# 如果可以融合,删除两元素,并在原位置插入新元素
if merge(list[a],list[a+1]) is not None:
list[a] = new_elem
del list[a+1]
a -= 1
return list
# 如果存在'>100kg'这样的情况,可以先转换成'100-infikg'进行处理,结束后再统一反转
mergedinput = mergelist(input) # 融合
三.你可能还需要…
①融合前整合数据
我们拿到手的数据,都是松散的,所以需要我们先整合再进行上述融合操作,pandas库的groupby函数可以帮我们做到这一点
I:
name | classify | weight |
---|---|---|
小王 | 手表 | 0-1kg |
小王 | 日用品 | 3-10kg |
小李 | 手机 | 1-3kg |
小王 | 日用品 | 1-3kg |
小李 | 手机 | <1kg |
小李 | 手机 | 10-30kg |
小李 | 手机 | 1-3kg |
O:
name | classify | weight |
---|---|---|
小王 | 手表 | 0-1kg |
小王 | 日用品 | 3-10kg,1-3kg |
小李 | 手机 | 1-3kg,<1kg,10-30kg,1-3kg |
outputDataframe = inputDataframe.groupby(['name','classify'])['weight'].apply(lambda x:x.str.cat(sep=',')).reset_index()
②融合后,无法融合的部分松散数据
对于无法融合成一条的多条规则,因为dataframe后续处理问题,我们也不能将这些规则继续挤在一行用逗号隔开,我们需要将他们拆成多行,保证每一行只有一个规则
I:
name | classify | weight |
---|---|---|
小王 | 手表 | 0-1kg |
小王 | 日用品 | 1-10kg |
小李 | 手机 | 0-3kg,10-30kg |
O:
name | classify | weight |
---|---|---|
小王 | 手表 | 0-1kg |
小王 | 日用品 | 1-10kg |
小李 | 手机 | 0-3kg |
小李 | 手机 | 10-30kg |
'''
本质上,使用numpy来存储累加数据,再重新转为dataframe
'''
newvalues=np.dstack((np.repeat(inputDataframe.name.values,list(map(len,inputDataframe.weight.values))),np.repeat(inputDataframe.classify.values,list(map(len,inputDataframe.weight.values))),np.concatenate(inputDataframe.weight.values)))
outputDataframe = pd.DataFrame(data=newvalues[0],columns=inputDataframe.columns)