How to remove a dict objects(letter) that remain in another str? - python

Suppose I have this dictionary:
x = {'a':2, 'b':5, 'g':7, 'a':3, 'h':8}`
And this input string:
y = 'agb'
I want to delete the keys of x that appear in y, such as, if my input is as above, output should be:
{'h':8, 'a':3}
My current code is here:
def x_remove(x,word):
x1 = x.copy() # copy the input dict
for i in word: # iterate all the letters in str
if i in x1.keys():
del x1[i]
return x1
But when the code runs, it removes all existing key similar as letters in word. But i want though there is many keys similar as letter in word , it only delete one key not every
wheres my wrong, i got that maybe but Just explain me how can i do that without using del function

You're close, but try this instead:
def x_remove(input_dict, word):
output_dict = input_dict.copy()
for letter in word:
if letter in output_dict:
del output_dict[letter]
return output_dict
For example:
In [10]: x_remove({'a': 1, 'b': 2, 'c':3}, 'ac')
Out[10]: {'b': 2}
One problem was your indentation. Indentation matters in Python, and is used the way { and } and ; are in other languages. Another is the way you were checking to see if each letter was in the list; you want if letter in output_dict since in on a dict() searches keys.
It's also easier to see what's going on when you use descriptive variable names.
We can also skip the del entirely and make this more Pythonic, using a dict comprehension:
def x_remove(input_dict, word):
return {key: value for key, value in input_dict if key not in word}
This will still implicitly create a shallow copy of the list (without the removed elements) and return it. This will be more performant as well.
As stated in the comments, all keys in dictionaries are unique. There can only ever be one key named 'a' or b.

Dictionary must have unique keys. You may use list of tuples for your data instead.
x = [('a',2), ('b',5), ('g',7), ('a',3), ('h',8)]
Following code then deletes the desired entries:
for letter in y:
idx = 0
for item in x.copy():
if item[0] == letter:
del x[idx]
break
idx += 1
Result:
>>> x
[('a', 3), ('h', 8)]

You can also implement like
def remove_(x,y)
for i in y:
try:
del x[i]
except:
pass
return x
Inputs x = {'a': 1, 'b': 2, 'c':3} and y = 'ac'.
Output
{'b': 2}

Related

Filter list of dictionaries by upper/lower limit on values

I have a list of dictionaries that I am trying to write a filter function for. The parameters to filter by will be given as a dictionary where the keys will be strings (matching the keys in the list of dictionaries to be filtered) and the values will be a list with an upper and lower limit.
Example list of dictionaries to be filtered:
test_list = [{'hello':1, 'goodbye':4}, {'hello':7, 'goodbye':6}, {'hello': 4, 'goodbye': 2}]
Example filtering parameters:
params = {'hello':[1, 6], 'goodbye':[5, 8]}
The function I've written is as follows:
def filter_list(target_list, **kwargs):
filtered_list = target_list
for k,v in kwargs.items():
for target in filtered_list:
if target[k]<v[0] or target[k]>v[1]:
filtered_list.remove(target)
return filtered_list
For some reason the second parameter is not being checked, and the output I get is:
filter_it = filter_list(test_list, **params)
print(filter_it)
>>[{'hello': 4, 'goodbye': 2}]
Why is this? By my reckoning none of the items in the list of dictionaries should pass the criteria. But if I change the parameters to:
params = {'hello':[1, 8], 'goodbye':[5, 8]}
The output is now:
>>[{'hello': 7, 'goodbye': 6}]
The real data this is going to be used on is a list of about 2500 dictionaries, each having about 45-50 key:value pairs. I need to be able to filter by an arbitrary number of parameters, as I won't always want to specify upper and lower limits on each, hence why I'm not hard-coding a comparison with each parameter.
Thanks in advance for all/any help!
Is this what you are looking for?
result = list(filter(lambda x: all(lower < x[key] < upper
for key, (lower, upper) in params.items()),
test_list))
You have a issue in this peice of code:
for target in filtered_list:
if target[k]>=v[0] and target[k]<=v[1]:
filtered_list.remove(target)
You are removing items from iterable Type which prevent you from certain loops... this is a way to filter a list you better do something like this:
filtered_list = [target for target in filtered_list if target[k]<v[0] or target[k]>v[1]]
You already got the answer, so I just give some additional explanation for you.
First, your code is deleting an item from a list while iterating over the list. So it will ignore some items. For example, when you delete the second item of a list. Then it will get the fourth item next loop.
I have modified your original code, so you can understand what it should be.
First, you can use copy instead move.
def filter_list_with_copy(target_list, **kwargs):
filtered_list = []
for target in target_list:
all_satisfied = True
for k, v in kwargs.items():
if target[k] < v[0] or target[k] > v[1]:
all_satisfied = False
break
if all_satisfied:
filtered_list.append(target)
return filtered_list
Second, you can use while instead for. Then you can control your loop index.
def filter_list_with_while(target_list, **kwargs):
filtered_list = target_list
for k, v in kwargs.items():
filtered_index = 0
filtered_list_length = len(filtered_list)
while filtered_index < filtered_list_length:
target = filtered_list[filtered_index]
if target[k] < v[0] or target[k] > v[1]:
filtered_list.remove(target)
filtered_list_length = len(filtered_list)
else:
filtered_index += 1
return filtered_list

How would I detect insertion of the same key with a different value into a dict?

So my goal for this problem is to, given 2 strings, str1 and str2, create a dictionary such that the characters in str1 are the keys and the corresponding characters in str2 are the values.
ie. crackthecode('apple','byytr') returns
{'a':'b','p':'y','l':'t','e':'r'}
and if it is inconsistent, ie. crackthecode('apple','byptr') then returns
{}, an empty dictionary.
This is my code, I'm just not sure how to do the inconsistent case.
PS. I cannot use zip for this question.
Below is my code.
def crackthecode(str1, str2):
final = {}
x = 0
for i in list(str1):
final[i]=str2[x]
x = x + 1
return final
All help is appreciated, thanks!
You can check if the key is already present in the dictionary, and compare the value with the new character. If they are not equal, return an empty dictionary. Otherwise, add the key-value pair to the dictionary.
You can use this code which uses the EAFP principle.
>>> def crackthecode(str1, str2):
final = {}
for i, key in enumerate(str1):
try:
if final[key] != str2[i]:
return {}
except KeyError:
final[key] = str2[i]
return final
>>> crackthecode('apple','byytr')
{'a': 'b', 'p': 'y', 'l': 't', 'e': 'r'}
>>> crackthecode('apple','byptr')
{}
Edit: Same code without using enumerate (requested by OP)
def crackthecode(str1, str2):
final = {}
for i in range(len(str1)):
try:
if final[str1[i]] != str2[i]:
return {}
except KeyError:
final[str1[i]] = str2[i]
return final

Finding if there are distinct elements in a python dictionary

I have a python dictionary containing n key-value pairs, out of which n-1 values are identical and 1 is not. I need to find the key of the distinct element.
For example: consider a python list [{a:1},{b:1},{c:2},{d:1}]. I need the to get 'c' as the output.
I can use a for loop to compare consecutive elements and then use two more for loops to compare those elements with the other elements. But is there a more efficient way to go about it or perhaps a built-in function which I am unaware of?
If you have a dictionary you can quickly check and find the first value which is different from the next two values cycling around the keys of your dictionary.
Here's an example:
def find_different(d):
k = d.keys()
for i in xrange(0, len(k)):
if d[k[i]] != d[k[(i+1)%len(k)]] and d[k[i]] != d[k[(i+2)%len(k)]]:
return k[i]
>>> mydict = {'a':1, 'b':1, 'c':2, 'd':1}
>>> find_different(mydict)
'c'
Otherwise, if what you have is a list of single-key dictionaries, then you can do it quite nicely mapping your list with a function which "extracts" the values from your elements, then check each one using the same logic.
Here's another working example:
def find_different(l):
mask = map(lambda x: x[x.keys()[0]], l)
for i in xrange(0, len(l)):
if mask[i] != mask[(i+1)%len(l)] and mask[i] != mask[(i+2)%len(l)]:
return l[i].keys()[0]
>>> mylist = [{'a':1},{'b':1},{'c':2},{'d':1}]
>>> find_different(mylist)
'c'
NOTE: these solutions do not work in Python 3 as the map function doesn't return a list and neither does the .keys() method of dictionaries.
Assuming that your "list of pairs" (actually list of dictionaries, sigh) cannot be changed:
from collections import defaultdict
def get_pair(d):
return (d.keys()[0], d.values()[0])
def extract_unique(l):
d = defaultdict(list)
for key, value in map(get_pair, l):
d[value].append(key)
return filter(lambda (v,l): len(l) == 1, d.items())[0][1]
If you already have your dictionary, then you make a list of all of the keys: key_list = yourDic.keys(). Using that list, you can then loop through your dictionary. This is easier if you know one of the values, but below I assume that you do not.
yourDic = {'a':1, 'b':4, 'c':1, 'd':1, }
key_list = yourDic.keys()
previous_value = yourDic[key_list[0]] # Making it so loop gets past first test
count = 0
for key in key_list:
test_value = yourDic[key]
if (test_value != previous_value) and count == 1: # Checks first key
print key_list[count - 1]
break
elif (test_value != previous_value):
print key
break
else:
previous_value = test_value
count += 1
So, once you find the value that is different, it will print the key. If you want it to print the value, too, you just need a print test_value statement

access value of a python dict() without knowing the keys

I have a dictionary of a list of dictionaries. something like below:
x = {'a':[{'p':1, 'q':2}, {'p':4, 'q':5}], 'b':[{'p':6, 'q':1}, {'p':10, 'q':12}]}
The length of the lists (values) is the same for all keys of dict x.
I want to get the length of any one value i.e. a list without having to go through the obvious method -> get the keys, use len(x[keys[0]]) to get the length.
my code for this as of now:
val = None
for key in x.keys():
val = x[key]
break
#break after the first iteration as the length of the lists is the same for any key
try:
what_i_Want = len(val)
except TypeError:
print 'val wasn't set'
i am not happy with this, can be made more 'pythonic' i believe.
This is most efficient way, since we don't create any intermediate lists.
print len(x[next(iter(x))]) # 2
Note: For this method to work, the dictionary should have atleast one key in it.
What about this:
val = x[x.keys()[0]]
or alternatively:
val = x.values()[0]
and then your answer is
len(val)
Some of the other solutions (posted by thefourtheye and gnibbler) are better because they are not creating an intermediate list. I added this response merely as an easy to remember and obvious option, not a solution for time-efficient usage.
Works ok in Python2 or Python3
>>> x = {'a':[{'p':1, 'q':2}, {'p':4, 'q':5}], 'b':[{'p':6, 'q':1}, {'p':10, 'q':12}]}
>>> next(len(i) for i in x.values())
2
This is better for Python2 as it avoids making a list of the values. Works well in Python3 too
>>> next(len(x[k]) for k in x)
2
Using next and iter:
>>> x = {'a':[{'p':1, 'q':2}, {'p':4, 'q':5}], 'b':[{'p':6, 'q':1}, {'p':10, 'q':12}]}
>>> val = next(iter(x.values()), None) # Use `itervalues` in Python 2.x
>>> val
[{'q': 2, 'p': 1}, {'q': 5, 'p': 4}]
>>> len(val)
2
>>> x = {}
>>> val = next(iter(x.values()), None) # `None`: default value
>>> val is None
True
>>> x = {'a':[{'p':1, 'q':2}, {'p':4, 'q':5}], 'b':[{'p':6, 'q':1}, {'p':10, 'q':12}]}
>>> len(x.values()[0])
2
Here, x.values gives you a list of all values then you can get length of any one value from it.

Is there a better way to compare dictionary values

I am currently using the following function to compare dictionary values and display all the values that don't match. Is there a faster or better way to do it?
match = True
for keys in dict1:
if dict1[keys] != dict2[keys]:
match = False
print keys
print dict1[keys],
print '->' ,
print dict2[keys]
Edit: Both the dicts contain the same keys.
If the true intent of the question is the comparison between dicts (rather than printing differences), the answer is
dict1 == dict2
This has been mentioned before, but I felt it was slightly drowning in other bits of information. It might appear superficial, but the value comparison of dicts has actually powerful semantics. It covers
number of keys (if they don't match, the dicts are not equal)
names of keys (if they don't match, they're not equal)
value of each key (they have to be '==', too)
The last point again appears trivial, but is acutally interesting as it means that all of this applies recursively to nested dicts as well. E.g.
m1 = {'f':True}
m2 = {'f':True}
m3 = {'a':1, 2:2, 3:m1}
m4 = {'a':1, 2:2, 3:m2}
m3 == m4 # True
Similar semantics exist for the comparison of lists. All of this makes it a no-brainer to e.g. compare deep Json structures, alone with a simple "==".
If the dicts have identical sets of keys and you need all those prints for any value difference, there isn't much you can do; maybe something like:
diffkeys = [k for k in dict1 if dict1[k] != dict2[k]]
for k in diffkeys:
print k, ':', dict1[k], '->', dict2[k]
pretty much equivalent to what you have, but you might get nicer presentation for example by sorting diffkeys before you loop on it.
You can use sets for this too
>>> a = {'x': 1, 'y': 2}
>>> b = {'y': 2, 'x': 1}
>>> set(a.iteritems())-set(b.iteritems())
set([])
>>> a['y']=3
>>> set(a.iteritems())-set(b.iteritems())
set([('y', 3)])
>>> set(b.iteritems())-set(a.iteritems())
set([('y', 2)])
>>> set(b.iteritems())^set(a.iteritems())
set([('y', 3), ('y', 2)])
Uhm, you are describing dict1 == dict2 ( check if boths dicts are equal )
But what your code does is all( dict1[k]==dict2[k] for k in dict1 ) ( check if all entries in dict1 are equal to those in dict2 )
Not sure if this helps but in my app I had to check if a dictionary has changed.
Doing this will not work since basically it's still the same object:
val={'A':1,'B':2}
old_val=val
val['A']=10
if old_val != val:
print('changed')
Using copy/deepcopy works:
import copy
val={'A':1,'B':2}
old_val=copy.deepcopy(val)
val['A']=10
if old_val != val:
print('changed')
If your values are hashable (ie. strings), then you can simply compare the ItemsView of the two dicts.
https://docs.python.org/3/library/stdtypes.html#dict-views
set_with_unique_key_value_pairs = dict1.items() ^ dict2.items()
set_with_matching_key_value_pairs = dict1.items() & dict2.items()
Any set operations are available to you.
Since you might not care about keys in this case, you can also just use the ValuesView (again, provided the values are hashable).
set_with_matching_values = dict1.values() & dict2.values()
>>> a = {'x': 1, 'y': 2}
>>> b = {'y': 2, 'x': 1}
>>> print a == b
True
>>> c = {'z': 1}
>>> print a == c
False
>>>
If you're just comparing for equality, you can just do this:
if not dict1 == dict2:
match = False
Otherwise, the only major problem I see is that you're going to get a KeyError if there is a key in dict1 that is not in dict2, so you may want to do something like this:
for key in dict1:
if not key in dict2 or dict1[key] != dict2[key]:
match = False
You could compress this into a comprehension to just get the list of keys that don't match too:
mismatch_keys = [key for key in x if not key in y or x[key] != y[key]]
match = not bool(mismatch_keys) #If the list is not empty, they don't match
for key in mismatch_keys:
print key
print '%s -> %s' % (dict1[key],dict2[key])
The only other optimization I can think of might be to use "len(dict)" to figure out which dict has fewer entries and loop through that one first to have the shortest loop possible.
If your dictionaries are deeply nested and if they contain different types of collections, you could convert them to json string and compare.
import json
match = (json.dumps(dict1) == json.dumps(dict2))
caveat- this solution may not work if your dictionaries have binary strings in the values as this is not json serializable

Categories