Generating "friend circles" from a dict of connections [python]

时间:2016-04-04 18:52:08

标签: python dictionary

I have a dict of Facebook friends that looks like this:

connections = {
0: set([3, 4]), 
1: set([5]), 
2: set([]),
3: set([0, 4, 6]), 
4: set([0, 3]), 
5: set([1]), 
6: set([3])}

where this dict matches a person (i.e. 3) to his friends (0, 4, 6). Now, I want to create a set of "friend circles" such that EVERY PERSON in the friend circle is friends with EVERY OTHER PERSON in the friend circle. It should look like this: {{0, 3, 4}, {3, 4}, {0, 4}, {0, 3}, {1, 5}, ...} Is there a simple way to accomplish this?

2 个答案:

答案 0 :(得分:2)

from itertools import chain, combinations, product

connections = {
    0: set([3, 4]),
    1: set([5]),
    2: set([]),
    3: set([0, 4, 6]),
    4: set([0, 3]),
    5: set([1]),
    6: set([3])
}

# Generate initial friend circles a generator that yields (0, 3, 4), (1, 5), (2,) etc.
# Please keep in mind that this gets exhausted after one run,
#   if you want to reuse friend_circles later just use a list ([] instead of ())
friend_circles = (tuple(set([k]+list(v))) for (k, v) in connections.iteritems())

# Slightly modified version of python powerset recipe
# https://docs.python.org/2/library/itertools.html#recipes
# min_size is to specify the minimum number of people required to form a circle (2 friends in your example).
# The function further filters the resulting powerset by checking that all the members of the circle are friends with each other.
def get_valid_circles(iterable, min_size):
    s = list(iterable)
    return [
        combo for combo in chain.from_iterable(combinations(s, r) for r in xrange(min_size, len(s)+1))
        if all(p2 in connections.get(p1, set()) for (p1, p2) in filter(lambda c: c[0] != c[1], product(combo, combo)))
    ]

# After retrieving all the valid circles you will end up with dupes as well as some empty sets of circles, so
# Filter the chain of circles and cast it into a set.
circles = set(
    filter(None, chain(*(get_valid_circles(friend_circle, 2) for friend_circle in friend_circles)))
)
print "Final filtered circles"
print circles

# If you want the unfiltered results you can just use this:
#   if you come up with an empty result here, see my note above on friend_circles generator
# print "Final unfiltered circles"
# print [get_valid_circles(friend_circle, 2) for friend_circle in friend_circles]

打印

Final filtered circles
set([(0, 3, 4), (1, 5), (3, 6), (0, 4), (0, 3), (3, 4)])

答案 1 :(得分:0)

您首先需要展开所有朋友集,因此对于人0,他的朋友集会成为

{0,3}, {0,4}, {0,3,4}

1成为:

{1,5}

3成为:

{3,0}, {3,4}, {3,6}, {3,0,4}, {3,0.6}, {3,4,6}, {3,0,4,6}

一旦你扩展了所有这些,然后再次遍历每个人,并检查扩展好友集中的每个朋友,看看他们是否也包含相同的扩展好友集。如果朋友集中的每个朋友都包含该朋友集,则它是朋友圈。存储这些朋友圈。如果需要,可以通过检查是否有任何圆圈是其他圆圈来删除子圆圈。例如{0,3}{0,3,4}的子集,因此可以将其删除。