2

I have a function such that there is a dictionary as parameters, with the value associated to be an integer. I'm trying to remove the minimum element(s) and return a set of the remaining keys.

I am programming in python. I cant seem to remove key value pairs with the same key or values. My code does not work for the 2nd and 3rd example This is how it would work:

remaining({A: 1, B: 2, C: 2})
{B, C}

remaining({B: 2, C : 2})
{}
remaining({A: 1, B: 1, C: 1, D: 4})
{D}

This is what I have:

def remaining(d : {str:int}) -> {str}:
    Remaining = set(d)
    Remaining.remove(min(d, key=d.get))
    return Remaining
Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
Ved Kirloskar
  • 25
  • 1
  • 5
  • You forgot the relevant tag for programming language. Also you forgot to mention what is your problem, do you get an error ? where are you stuck ? – Nir Alfasi Jan 18 '15 at 19:03
  • Python! I am stuck on removing key value pairs where the values are the same. Examples 2 and 3 in the description are where I am having trouble – Ved Kirloskar Jan 18 '15 at 19:06

5 Answers5

2

One approach is to take the minimum value, then build a list of keys that are equal to it and utilise dict.viewkeys() which has set-like behaviour and remove the keys matching the minimum value from it.

d = {'A': 1, 'B': 1, 'C': 1, 'D': 4}

# Use .values() and .keys() and .items() for Python 3.x
min_val = min(d.itervalues())
remaining = d.viewkeys() - (k for k, v in d.iteritems() if v == min_val)
# set(['D'])

On a side note, I find it odd that {B: 2, C : 2} should be {} as there's not actually anything greater for those to be the minimum as it were.

Jon Clements
  • 138,671
  • 33
  • 247
  • 280
  • [Pretty sure it's 3 from the annotation syntax.] – DSM Jan 18 '15 at 19:31
  • @DSM I kind of glossed over that bit... not sure `{str:int}` looks quite right... but never really had a reason to both with annotations as of yet (If I need it, the docs are there...) – Jon Clements Jan 18 '15 at 19:39
0

That's because you're trying to map values to keys and map allows different keys to have the same values but not the other way! you should implement a map "reversal" as described here, remove the minimum key, and then reverse the map back to its original form.

from collections import defaultdict

# your example
l = {'A': 1, 'B': 1, 'C': 1, 'D': 4}

# reverse the dict
d1 = {}
for k, v in l.iteritems():
    d1[v] = d1.get(v, []) + [k]

# remove the min element
del d1[min(d1, key=d1.get)]

#recover the rest to the original dict minus the min
res = {}
for k, v in d1.iteritems():
    for e in v:
        res[e] = k

print res

Comment:
@Jon Clements's solution is more elegant and should be accepted as the answer

Community
  • 1
  • 1
Nir Alfasi
  • 53,191
  • 11
  • 86
  • 129
0

This removes all the items with the minimum value.

import copy

def remaining(dic):
    minimum = min([i for i in dic.values()])
    for k, v in copy.copy(dic.items()):
        if v == minimum: dic.pop(k)

    return set(dic.keys())
Malik Brahimi
  • 16,341
  • 7
  • 39
  • 70
  • OP wants a set() with all the keys but the ones whose value is the minimum. – Fernando Jan 18 '15 at 20:10
  • You can't change the size of dict while you iterate it. `dict.pop()` inside that `for` raises `RuntimeError: dictionary changed size during iteration` – Fernando Jan 18 '15 at 20:20
  • Yes you can, it's just not suggested. I'll make a copy anyway. – Malik Brahimi Jan 18 '15 at 20:21
  • 1
    It works in Python 2 because `dict.items()` is a list, but it raises an exception in Python 3 because `dict.items()` is a iterator (is like `dict.iteritems()` in Python 2). – Fernando Jan 18 '15 at 20:28
0

Take the minimum value and construct a set with all the keys which are not associated to that value:

def remaining(d):
    m = min(d.values())
    return {k for k,v in d.items() if v != m}

If you don't like set comprehensions that's the same as:

def remaining(d):
    m = min(d.values())
    s = set()
    for k,v in d.items():
        if v != m:
            s.add(k)
    return s
Fernando
  • 1,382
  • 8
  • 17
0

An easier way would be to use pd.Series.idxmin() or pd.Series.min(). These functions allow you to find the index of the minimum value or the minimum value in a series, plus pandas allows you to create a named index.

import pandas as pd
import numpy as np
A = pd.Series(np.full(shape=5,fill_value=0))#create series of 0
A = A.reindex(['a','b','c','d','e'])#set index, similar to dictionary names
A['a'] = 2
print(A.max())
#output 2.0
print(A.idxmax())#you can also pop by index without changing other indices
#output a
Jake
  • 683
  • 6
  • 5