I have a dictionary I would like to find the minimum key where value[1] is equal to a a specified string.
somedict = {'1': ['110', 'A'], '3': ['1', 'A'], '2': ['3', 'B'], '4': ['1', 'B']}
mindict = min(somedict.iteritems(), key=itemgetter(0) )
This gives me ('1', ['110', 'A'])
I would like to further filter this by finding the min key where value is 'B'
to give me the result ('2', ['3', 'B'])
How would go about this?
Use a generator expression filtering your items first:
min((i for i in somedict.iteritems() if i[1][-1] == 'B'), key=itemgetter(0))
The generator expression produces elements from somedict.iteritems() where the last entry in the value is equal to 'B'.
Note that there is a risk here that no items match your filter! If that could be the case, make sure you catch the ValueError thrown by min() when passed an empty sequence. If you are using Python 3.4 or newer, you can specify a default to be returned for that case:
min((i for i in somedict.iteritems() if i[1][-1] == 'B'),
key=itemgetter(0), default=())
which would return an empty tuple if no items have a last entry 'B' in their value.
Demo:
>>> from operator import itemgetter
>>> somedict = {'1': ['110', 'A'], '3': ['1', 'A'], '2': ['3', 'B'], '4': ['1', 'B']}
>>> min((i for i in somedict.iteritems() if i[1][-1] == 'B'), key=itemgetter(0))
('2', ['3', 'B'])
Related
I have a Python dictionary in this format :
mongo = {
1: {'syno': ['a','b','c'], 'can': ['2','3','4']},
2 :{'syno': ['x','y','z'], 'can': ['6','7','8']},
}
and I have a list called syno_iter:
syno_iter = ['a','b','c','d','e']
Using a single value in syno_iter, let's suppose a. I want to get the values in the can in the mongo{} as in if the value a is available in the value of the value syno, we can return can.
We don't have any way of knowing the keys of mongo dict. Also as dictionaries are not iterable we can't use range thing.
To reiterate:
I want to do something like this-
for i in syno_iter:
if i in (mongo.values('syno')):
print mongo.values('can'(values()))
input - 'a'
output - ['2','3','4']
You can perform a lookup like that with:
Code:
def get_syno_values(data, lookup):
for row in data.values():
if lookup in row['syno']:
return row['can']
Test Code:
mongo = {
1: {'syno': ['a', 'b', 'c'], 'can': ['2', '3', '4']},
2: {'syno': ['x', 'y', 'z'], 'can': ['6', '7', '8']}
}
syno_iter = ['a', 'b', 'c', 'd', 'e']
print(get_syno_values(mongo, 'a'))
print(get_syno_values(mongo, 'y'))
Results:
['2', '3', '4']
['6', '7', '8']
I am trying to generate lists from the elements of a list in python.
For example: there is a list with the following information:
list=['AB4', 'AB3','AC3', 'BC4', 'BC5']
This is the exact format of the elements of the list.
I suppouse to create list for every element, separate for the letters (considering both letters as one block) and separate for the numbers, that will contain the missing character from their string. Here is what I mean:
AB:['4', '3']
AC:['3']
BC:['4', '5']
4:['AB', 'BC']
3:['AB', 'AC']
5:['BC']
These are the lists that I should generate from the original list. There is no limitation to the elements of the original list, and their format is exactly like in the example "two letters and a number".
Thank you in advance.
You can use regexes (the re module) and a defaultdict to accomplish this. The following will work for arbitrary lengths of the non-digit/digit parts of your input strings:
import re
from collections import defaultdict
def str_dig(s): # str_dig('ABC345') -> ('ABC', '345')
return re.match('([^\d]+)(\d+)', s).groups()
lst=['AB4', 'AB3','AC3', 'BC4', 'BC5'] # do NOT shadow list!
d = defaultdict(list)
for x, y in map(str_dig, lst): # map applies the str_dig function to all in lst
d[x].append(y)
d[y].append(x)
# d['AB']: ['4', '3'], d['3']: ['AB', 'AC']
This will do it:
from collections import defaultdict
l=['AB4', 'AB3','AC3', 'BC4', 'BC5']
result=defaultdict(list)
for item in l:
#If you want numbers to be numbers and not strings replace item[2:] with int(item[2:])
result[item[:2]].append(item[2:])
result[item[2:]].append(item[:2])
And you can use this to print it just as you want:
import pprint
pp = pprint.PrettyPrinter()
pp.pprint(result)
output:
{'3': ['AB', 'AC'],
'4': ['AB', 'BC'],
'5': ['BC'],
'AB': ['4', '3'],
'AC': ['3'],
'BC': ['4', '5']}
How about this,
import itertools
import operator
l = ['AB4', 'AB3','AC3', 'BC4', 'BC5']
lists = [(s[:2], s[2]) for s in l] # [('AB', '4'), ('AB', '3'), ('AC', '3'), ('BC', '4'), ('BC', '5')]
results = dict()
for name, group in itertools.groupby(sorted(lists, key=operator.itemgetter(0)), key=operator.itemgetter(0)):
results[name] = map(operator.itemgetter(1), group)
for name, group in itertools.groupby(sorted(lists, key=operator.itemgetter(1)), key=operator.itemgetter(1)):
results[name] = map(operator.itemgetter(0), group)
print(results)
# Output
{ 'AC': ['3'],
'AB': ['4', '3'],
'BC': ['4', '5'],
'3': ['AB', 'AC'],
'5': ['BC'],
'4': ['AB', 'BC']}
I have a dictionary like this
dict = {'name':''xyz','c1':['a','b','r','d','c'],'c2':['21','232','11','212','34']}
Here dict.c1 values and dict.c2 values are inter-dependant. That is, 'a' is related to '21', 'd' is related to '212', 'b' is related to '232'...
I have to sort c1 and c2 should get reflected accordingly. The final output should be
dict = {'name':''xyz','c1':['a','b','c','d','r'],'c2':['21','232','34','212','11']}
What is the most efficient way to do this?
This works:
d = {'name': 'xyz','c1':['a','b','r','d','c'],'c2':['21','232','11','212','34']}
s = sorted(list(zip(d['c1'], d['c2'])))
d['c1'] = [x[0] for x in s]
d['c2'] = [x[1] for x in s]
Result:
{'c1': ['a', 'b', 'c', 'd', 'r'],
'c2': ['21', '232', '34', '212', '11'],
'name': 'xyz'}
UPDATE
The call to list is not needed. Thanks to tzaman for the hint. It was a relict of putting together the solution from separate steps.
d = {'name': 'xyz','c1':['a','b','r','d','c'],'c2':['21','232','11','212','34']}
s = sorted(zip(d['c1'], d['c2']))
d['c1'] = [x[0] for x in s]
d['c2'] = [x[1] for x in s]
Your data structure does not reflect the real relationship between its elements. I would start by merging c1 and c2 into an OrderedDict. It would take care of both the relationship and the order of elements. Like this:
dict = dict(
name='xyz',
c = OrderedDict(sorted(
zip(
['a','b','r','d','c'],
['21','232','11','212','34']
)
))
)
Frankly, the most efficient way is to store the data in a form compatible with its use. In this case, you would use a table (e.g. PANDAS data frame) or simply a list:
xyz_table = [('a', '21'), ('b'. 232'), ...]
Then you simply sort the list on the first element of each tuple:
xyz_table = [('a', '21'), ('b', '232'), ('c', '34'), ('d', '212'), ('r', '11')]
xyz_sort = sorted(xyz_table, key = lambda row: row[0])
print xyz_sort
You could also look up a primer on Python sorting, such as this
Here's one way you could do it, using zip for both joining and unjoining. You can re-cast them as lists instead of tuples when you put them back into the dictionary.
a = ['a','b','r','d','c']
b = ['21','232','11','212','34']
mix = list(zip(a, b))
mix.sort()
a_new, b_new = zip(*mix)
>>> a_new
('a', 'b', 'c', 'd', 'r')
>>> b_new
('21', '232', '34', '212', '11')
I'm trying to count the amount of values that contain numbers that show up in the values of dictionary entries, and then put them in a list. So for example:
some_dictionary = {'FIRST' : ['a', '1', 'b', '2'],
'SECOND' : ['c', 'd', '3', 'e'],
'THIRD' : ['4', '5', 'f', 'g6']}
some_dictionary_values = [2, 1, 3]
So far I have:
for key, value in some_dictionary.items():
for string in value:
if any(char.isdigit() for char in string):
amount_of_numbers.append(string)
but this seems like a really roundabout way of doing it. I'd like to know if I'm on the right track or if there's an easier way of going about this.
edit: I guess my question wasn't very clear. Let me give another example:
dictionary = {'ONE' : ['abc', '123', 'def']
'TWO' : ['happy', '42', 't4']
'THREE' : ['word2', 'word', 'words']}
So the key 'ONE' has the values 'abc', '123', and 'def'. Of these values, only one of them contains a number, so in the list this would show up as 1.
The key 'TWO' has two values which contain numbers, '42' and 't4'.
The key 'THREE' has one value which contains a number, 'word2'.
Therefore the final list will be:
final_list = [1, 2, 1]
I hope that made my problem clearer.
Edited Answer
amount_of_numbers = {}
for key, value in some_dictionary.items():
amount_of_numbers[key] = len ([string for string in value if all(char.isdigit() for char in string) ])
print amount_of_numbers
{'SECOND': 1, 'THIRD': 2, 'FIRST': 2}
Original Answer
Here you go:
some_dictionary = {'FIRST' : ['a', '1', 'b', '2'],
'SECOND' : ['c', 'd', '3', 'e'],
'THIRD' : ['4', '5', 'f', 'g6']}
amount_of_numbers = []
for value in some_dictionary.values():
amount_of_numbers += [string for string in value if all(char.isdigit() for char in string)]
print amount_of_numbers
['3', '4', '5', '1', '2']
Note that your current implementation is incorrect, it includes g6 also in the output, even though it is not a number
This one-liner utilizes the fact that in arithmetical expressions boolean behaves as integer
{key: sum(any(c.isdigit() for c in word) for word in value)
for key, value in some_dictionary.iteritems()}
You may saw this kind of questions a lot, but my demand here is different.
Say I have a dictionary d = {'1': 'stack', '2': 'over', '3': 'flow'}, and I want to make a tuple like t = ('1', 'stack', '2', 'over', '3', 'flow')
What's the simplest way to do it?
You can use itertools.chain. Note that this tuple will not have reproducible order, because dictionaries don't have one:
In [1]: d = {'1': 'stack', '2': 'over', '3': 'flow'}
In [2]: from itertools import chain
In [3]: tuple(chain.from_iterable(d.items()))
Out[3]: ('1', 'stack', '3', 'flow', '2', 'over')
In Python 2.x, you can use d.iteritems() instead of d.items().
Edit: As EdChum notes in the comment, you can ensure the order by applying sorted to the items. Note, however, that by default strings are sorted in lexicographical order:
In [4]: sorted(['2', '10'])
Out[4]: ['10', '2']
You can override this by providing the key parameter to sorted:
In [5]: key = lambda i: (int(i[0]), i[1])
In [6]: tuple(chain.from_iterable(sorted(d.items(), key=key)))
Out[6]: ('1', 'stack', '2', 'over', '3', 'flow')