python处理list中set,获取最大并集的所有集合

       前一阵子在搞数据分析的时候,碰到了这样的需求,有n种物品,m个人,每个人会买过n种物品中的多个,只要两个人之间有买过相同物品,无论几个,我们就把他当做一类人。即便a和b两个人之间没有买过相同的物品,c都买过a和b中的物品,那么a,b,c都可看成一类人。具体形式如下:list = [{1,4,7},{2,5,7},{1,5,6},{9,11,23},{4,23,39},{34,6,10}]

       list中的set代表人的购物情况(该示例中有len(list)个人),一个set中的数据,如{1,4,7}则代表当前人所购物的物品索引是1,4,7,(肯定不会写:苹果,梨,手机之类的真实内容)。我们需要得出的结果是:[{1,4,7,2,5,1,6,34,10},{9,11,23},{4,23,39}] 其含义为:购买1,4,7,2,5,,6,34,10物品的为一类人,购买9,11,23物品的为一类人,购买4,23,39物品的为一类人。emm..就是这样

主体思想就是:如果两个set取交集不为空,那么取两者并集当做一个新的集合。

提供两种解决方式:

其一:递归,代码如下:

# one 为待处理的list集合
finallist = [] # 处理后的存储集合
one.apend({len(one)})  # 在尾部增加一个集合(list的长度,为了保证递归算法的退出)
# 递归算法
def dealwithlist(first, one):
    residue = []
    if len(one) > 0:
        for i in range(0, len(one)):
            if first & one[i]:
                first = first | one[i]
            else:
                residue.append(one[i])
        # 每次循环完一轮就判断是否含有这个set
        if finallist.__contains__(first):
            if len(residue) > 1:  # 对剩余的list集合做取并
                finallist.insert(0, finallist[-1])  # 选择在头部插入finalist最后一个
                dealwithlist(residue[0], residue)
                return
            else: # 如果只剩下无用的那个集合,则退出
                return
        else:
            if len(finallist) > 0:
                finallist.pop(-1)  # 删除finalist最后一个位置
            finallist.append(first)
    dealwithlist(first, residue)

one.pop(-1) # 得到最后的结果集

递归的弊端也是很明显:当数据量变大,比较次数增多的时候,会超出最大递归深度,进而出现栈溢出的问题!待大神解决

 

 

其二:动态改变list:

list_a为待处理的list

def set_group(list_a):
    tgt = []
    # 遍历所有元素,进行分组
    for i, x in enumerate(list_a):
        z = x  # 暂存当前元素
        flag = []  #

        # 如果目标库不为空,遍历目标库,看是否存在有交集的元素
        if len(tgt) > 0:
            for j, y in enumerate(tgt):
                # 判断是否存在交集
                if z.intersection(y):
                    z = z.union(y)
                    # 若存在并集,则将当前元素记录
                    flag.append(j)

                    # 如果存在已有的元素,删除原有的元素
            if len(flag) > 0:
                flag.reverse()  # 之所以要倒排一下,是防止list删除元素后的遍历异常
                for k in flag:
                    tgt.pop(k)

        tgt.append(z)
    return tgt

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值