1

I haven't taken python in a long time and am a bit rusty but for the first question I'm taking a dictionary and need to intersect it returning the key and the value. So for example, I'm entering

a = {1:'a1', 2.5:'a2', 4:'a3'}
b = {1:'a1', 3:'a2',  5:'a4'}

If I enter c = intersect(a,b), I want it to return {1:'a1'}, but I only get back {'a1'}.

My code so far is:

def intersect(a, b):
    for i in a:
        if j in b:
            if a[i]==b[i]:
                return ({i})
        else:
            return {}
martineau
  • 119,623
  • 25
  • 170
  • 301

2 Answers2

6

You could simplify this, using actual set intersection. This retains only shared items (key and value the same):

def intersect(a, b):
    return dict(a.items() & b.items())

If your dict params have non-hashable values, you can go for a dict comprehension along the following lines:

def intersect(a, b):
    return {k: a[k] for k in a if b.get(k, not a[k]) == a[k]}

And you can fix your original approach like so:

def intersect(a, b):
    d = {}
    for i in a:
        if i in b and a[i] == b[i]:
            d[i] = a[i]
    return d
user2390182
  • 72,016
  • 6
  • 67
  • 89
  • Could you tell me why you used items and dict? In my first code I wrote the same things except I didn't have those two included. –  Jan 14 '18 at 02:32
  • @coco_11 `set(a)` is equivalent to `set(x for x in a)` and if `a` is a `dict`, this will only produce its keys. Hence the `items` call. And since items are a list of pairs, you have to call `dict` on it again. – user2390182 Jan 14 '18 at 02:37
  • 2
    In Python 3, items aren't given as a list. Try `dict(a.items() & b.items())`. – Stefan Pochmann Jan 14 '18 at 02:44
  • 1
    @StefanPochmann True, but the solution given in my answer works in both Py 2 and 3. And the question is not tagged with a specific version. – user2390182 Jan 14 '18 at 02:46
  • Yeah I just meant your comment "items are a list of pairs" – Stefan Pochmann Jan 14 '18 at 02:48
  • @StefanPochmann Yeah, the point there was on the pairs. Whatever the type of iterable, if it produces pairs, you can pass it to the `dict` constructor. – user2390182 Jan 14 '18 at 02:49
  • 1
    FWIW, I think the `if b.get(k, not a[k]) == a[k]` is ingenious. – martineau Mar 28 '21 at 19:00
  • **From 2021:** Python 2 is thankfully long dead, so `dict(a.items() & b.items())` is the correct approach. Coercing *two* `ItemsView` containers into sets needlessly consumes space and time. – Cecil Curry Apr 01 '21 at 06:24
5

Here is a version of the intersect function, that intersects the keys and uses the values of the first dictionary, that means in case of different values, this function is biased towards the value in the first dictionary:

def intersect(a, b):
    return {k: a[k] for k in a.keys() & b.keys()}

This works because, the dict_keys view objects returned by dict.keys() (since Python 3) are sets (i.e. implement collections.abc.Set).

If you want to customize, which value will be used, we can use a function, that takes both values:

def intersect(a, b, select=lambda a, b: a):
    return {k: select(a[k], b[k]) for k in a.keys() & b.keys()}

Instead of returning one of the values, we could then also e.g. add the values:

>>> intersect({'a': 4, 'b': 3}, {'a': 5}, lambda a, b: a + b)
{'a': 9}
Sebastian Schrader
  • 1,453
  • 15
  • 19