Vcoss
Vcoss

Reputation: 43

How to check which values have overlapping keys in a dictionary?

I have a dictionary:

{0: [1, 2, 3, 4, 5, 6, 7, 8, 9], 1: [0, 9, 4, 6, 7], 2: [8, 9, 3, 6, 0], 3: [8, 9, 2, 0], 4: [8, 0, 1, 6, 7], 5: [0, 9], 6: [8, 0, 2, 4, 1], 7: [8, 0, 4, 1], 8: [0, 2, 3, 4, 6, 7], 9: [0, 1, 2, 3, 5]}

And then I take an input which references one of the keys:

flag = 0
user = input("Enter an integer for a user ID: ")
if isinstance(user, float):
    flag = 1
if user.isdigit() and int(user) >= 0 and int(user) <= (len(network)-1) and flag == 0:
    return(user)
else:
    while user.isdigit() == False or int(user) < 0 or int(user) > (len(network)-1):
        user = input("Enter an integer for a user ID: ")

So now I need to help to understand to find the values with overlapping keys, for example, if the user chooses 4 the code would output:

"For user with ID 4 we recommend the user with ID 2"
"That is because users 4 and 2 have 3 common friends and user 4 does not have more common friends with anyone else."

Also the users cannot know each other. So even though 4 has more in common with 0, they know each other and therefore do not work.

Thanks!

Upvotes: 0

Views: 1971

Answers (2)

Van Peer
Van Peer

Reputation: 2167

Approach:

  1. Function matchMaker(id, d) which accepts the id and d
  2. Loop through key-value pairs in d
  3. Checks if key is not same as the id
  4. Checks if id's know each other
  5. Finds the common friends between id and every other id; appends to list l2
  6. If match exists finds all and returns the list matches else []

Code

d={0: [1, 2, 3, 4, 5, 6, 7, 8, 9], 1: [0, 9, 4, 6, 7], 2: [8, 9, 3, 6, 0], 3: [8, 9, 2, 0], 4: [8, 0, 1, 6, 7], 5: [0, 9], 6: [8, 0, 2, 4, 1], 7: [8, 0, 4, 1], 8: [0, 2, 3, 4, 6, 7], 9: [0, 1, 2, 3, 5]}

def matchMaker(id, d):
    l2=[]
    for k,v in d.items():
        if k!=id:
            if id not in v:
                f = set(d[id]).intersection(v)
                l2.append([len(f), k])        # append f if you want the suggestions
    matches=[]
    if l2:
        match_count = max(l2)[0]
        matchid = max(l2)[1]
        matches = [matchid]

        for item in l2:
            if item[1] not in matches:
                if match_count == item[0]:
                    matches.append(item[1])
    return matches

id=5
all_matches = matchMaker(id,d)

print(all_matches)

To obtain the integer value of id, use all_matches[0], all_matches[1] etc.

Output

# matches for id = 5
[3, 1, 2]

# matches for id = 4
[2]

Upvotes: 2

Paul Panzer
Paul Panzer

Reputation: 53029

The easiest is to convert your friend lists to sets. You can do this using a dict comprehension like so

d  = {0: [1, 2, 3, 4, 5, 6, 7, 8, 9], 1: [0, 9, 4, 6, 7], 2: [8, 9, 3, 6, 0], 3: [8, 9, 2, 0], 4: [8, 0, 1, 6, 7], 5: [0, 9], 6: [8, 0, 2, 4, 1], 7: [8, 0, 4, 1], 8: [0, 2, 3, 4, 6, 7], 9: [0, 1, 2, 3, 5]}
ds = {k:set(v) for k, v in d.items()}

Now you can find the shared friends of, say, 2 and 4 by intersecting

ds[2] & ds[4]

-> {0, 8, 6}

and you can count them using len

len(ds[2] & ds[4])

Finally, you can make a loop to find the best match (a is the input, b is the output):

def best_match_for(a):
    b = None
    af = ds[a]
    best = -1
    for k, v in ds.items():
        if k!=a and not k in af:
            ovlp = len(af & v)
            if ovlp > best:
                best = ovlp
                b = k
    return b, best if best > 0 else None

Upvotes: 1

Related Questions