我在python中有一个类似下面的列表(真正的一个是巨大的,我只能通过查看它才能做到这一点):
original1=[['email', 'tel', 'fecha', 'descripcion', 'categ'],
['a@gmail.com', '1', '2014-08-06 00:00:06', 'MySpace a', 'animales'],
['b@gmail.com', '1', '2014-08-01 00:00:06', 'My Space a', 'ropa'],
['a@gmail.com', '2', '2014-08-06 00:00:06', 'My Space b', 'electronica'],
['b@gmail.com', '3', '2014-08-10 00:00:06', 'Myace c', 'animales'],
['c@gmail.com', '4', '2014-08-10 00:00:06', 'Myace c', 'animales']]
我在数据和名称之间拆分它以处理数据:
datos=original1[-(len(original1)-1):len(original1)]
我需要做一个包含所有重复项的字典,考虑电子邮件和电话,但我需要应用传递性:因为如果我们考虑电子邮件,第0行=第2行,如果我们考虑电话,则行第1行,和行1 =第3行如果我们再次考虑电子邮件,我需要知道在这种情况下所有候选人都是0,1,2和3,而4则是单独的。
我创建了以下代码:
from collections import defaultdict
email_to_indices = defaultdict(list)
phone_to_indices = defaultdict(list)
for idx, row in enumerate(datos):
email = row[0].lower()
phone = row[1]
email_to_indices[email].append(idx)
phone_to_indices[phone].append(idx)
所以现在我需要应用传递规则,将0到3和4个单独聚在一起。
如果您打印
print 'email', email_to_indices
print 'phone', phone_to_indices
你得到:
电子邮件defaultdict(,{' a@gmail.com':[0,2],' b@gmail.com': [1,3],' c@gmail.com':[4]})
手机默认用户(,{' 1':[0,1],' 3':[3],' 2':[2], ' 4':[4]})
不知道如何让那些考虑传递性财产的人联合起来。 我需要得到类似的东西:
first_group:[0,1,2,3]
second_group:[4]
谢谢!
答案 0 :(得分:2)
这里有一个图表,或者Bipartite graph更准确。节点有两种类型:电子邮件和电话。如果存在具有该电子邮件和电话的记录,则连接两个节点。或者我们甚至可以说记录本身就是连接两个节点的边缘。
任务是找到此图表的Connected components。通过链接,您可以找到可以在线性时间内完成的算法。
当然,也可以发明一些快速而肮脏的解决方案,如果您的数据集足够小,甚至可能认为是合适的。
您可以在此处找到一些Python实现:Python connected components
更新:以下是如何构建图表的示例:
graph = {};
EMAIL = "email";
PHONE = "phone";
for rec in datos:
graph.setdefault((EMAIL, rec[0]), set()).add((PHONE, rec[1]));
graph.setdefault((PHONE, rec[1]), set()).add((EMAIL, rec[0]));
print "\n".join("%s: %s" % (str(node), str(linkedNodes)) for (node, linkedNodes) in graph.iteritems());
因此每个节点都有一个类型(EMAIL
或PHONE
,它们实际上可以只是整数,例如0和1,我只为了很好的打印而使它们成为字符串)和一个值。 Graph是一个字典,其中节点作为键,连接节点集作为值。
答案 1 :(得分:0)
这是另一种方法:
在构建email_to_indices
字典时,可以将该行的电话号码存储为值,然后让phone_to_indices
具有该行的索引。这样我们就可以为行地图创建email_to_indices
到phone_to_indices
的索引。
通过这种修改和基本的设置操作,我能够得到你想要的东西:
from collections import defaultdict
email_to_indices = defaultdict(list)
phone_to_indices = defaultdict(list)
combined = defaultdict(set)
original=[['email', 'tel', 'fecha', 'descripcion', 'categ'],
['a@gmail.com', '1', '2014-08-06 00:00:06', 'MySpace a', 'animales'],
['b@gmail.com', '1', '2014-08-01 00:00:06', 'My Space a', 'ropa'],
['a@gmail.com', '2', '2014-08-06 00:00:06', 'My Space b', 'electronica'],
['b@gmail.com', '3', '2014-08-10 00:00:06', 'Myace c', 'animales'],
['c@gmail.com', '4', '2014-08-10 00:00:06', 'Myace c', 'animales']]
for idx, row in enumerate(original[1:], start=1):
email = row[0].lower()
phone = row[1]
email_to_indices[email].append(phone) # Here is what I changed
phone_to_indices[phone].append(idx)
random_key = 0
for idx, row in enumerate(original[1:], start=1):
grouped_rows = []
if row[0].lower() in email_to_indices:
for phone_no in email_to_indices[row[0].lower()]:
grouped_rows.extend(phone_to_indices[phone_no])
if len(combined[random_key]) > 0 and len(set(grouped_rows).intersection(combined[random_key])) > 0:
combined[random_key].update(set(grouped_rows))
elif len(combined[random_key]) > 0:
random_key += 1
combined[random_key].update(set(grouped_rows))
else:
combined[random_key].update(set(grouped_rows))
print combined
这给出了:
defaultdict(<type 'set'>, {0: set([1, 2, 3, 4]), 1: set([5])})