Related
I am a student in a python course where we created a list of tuples (containing 2 elements) that we're trying to manipulate in various ways. In addition, we are to convert those tuple elements into a dictionary and re-create the manipulations using the dictionary and avoiding for loops. The task I'm stuck on is that given a specific id (which could be a key OR value in the dictionary) the function returns all the other keys/values that are found in that dictionary.
It doesn't seem efficient to use a dictionary for this, but that's the section we are on in the course and is specifically asked by the assignment. Also no for loops (if that is possible?). Recall that the id can be either a key or a value in the dictionary.
example_dictionary = {'A': 'C', 'R': 'E', 'D': 'A', 'L': 'R', 'C': 'D'}
def get_interactions(example_dictionary, id):
output = ''
for j,k in example_dictionary.items():
if j == id:
output = output + k + ' '
if k == id:
output = output + j + ' '
return output
This code works just fine, however it 1) has a for loop (no good) and 2) isn't very pythonic (kind of an eyesore)! How could I use the dictionary more efficiently and condense down my lines? I am in Python 3, Thank you!
Expected result
Having one dictionary and value named wanted, you want to create another dict being copy of
original one with removed all items not having key or value equal to wanted value.
It can be expressed in form of pytest test case with couple of scenarios.
import pytest
scenarios = [
[
# dct
{'A': 'C', 'R': 'E', 'D': 'A', 'L': 'R', 'C': 'D'},
# wanted
"A",
# expected (result)
{'A': 'C', 'D': 'A'},
],
[
# dct
{'A': 'C', 'R': 'E', 'D': 'A', 'L': 'R', 'C': 'D'},
# wanted
"E",
# expected (result)
{'R': 'E'},
],
[
# dct
{'A': 'C', 'R': 'E', 'D': 'A', 'L': 'R', 'C': 'D'},
# wanted
"D",
# expected (result)
{'D': 'A', 'C': 'D'},
],
[
# dct
{'A': 'C', 'R': 'E', 'D': 'A', 'L': 'R', 'C': 'D'},
# wanted
"nothere",
# expected (result)
{},
],
[
# dct
{'A': 'C', 'R': 'E', 'D': 'A', 'L': 'R', 'C': 'D'},
# wanted
"A",
# expected (result)
{'A': 'C', 'D': 'A'},
],
]
# replace with real implementation
def get_key_or_val_itms(dct, wanted):
# something comes here
return result
#pytest.mark.parametrize("scenario", scenarios)
def test_it(scenario):
dct, wanted, expected = scenario
assert get_key_or_val_itms(dct, wanted) == expected
Do not bother with anything apart from scenarios. It lists couple of test scenarios with input
dictionary, value for wanted and expected result.
Building stones for the solution
dict.items() - dict to list of tuples
>>> dct = {'A': 'C', 'R': 'E', 'D': 'A', 'L': 'R', 'C': 'D'}
>>> dct.items()
[('A', 'C'), ('R', 'E'), ('D', 'A'), ('L', 'R'), ('C', 'D')]
testing membership of a value in a tuple/list
>>> 'A' in ('A', 'C')
True
>>> 'A' in ('R', 'E')
False
Lambda function testing, if wanted is present in a tuple
lambda allows "in place" function definition. It is often used in places,
where some functions expects reference to a function.
First, create named function tuple_wanted
>>> wanted = "A"
>>> def tuple_wanted(tpl):
... return wanted in tpl
and test it (note, that wanted has now value "A"):
>>> tuple_wanted(('A', 'C'))
True
>>> tuple_wanted(('R', 'E'))
False
Now create the function. To play with it, we store the result of lambda in fun:
>>> fun = lambda tpl: wanted in tpl
It can be used in the same manner a tuple_wanted before:
>>> fun(('A', 'C'))
True
>>> fun(('R', 'E'))
False
Later on we will use the result of lambda directly (see filter) without
storing it into any variable.
filter removing all list items not passing some test
filter gets test function and iterable (e.g. list of items) to test by it.
Result of calling filter is list of items from the iterable, which passed the test.
In our case, we want to pass only the tuples, containing wanted value (e.g. "A")
>>> filter(tuple_wanted, dct.items())
[('A', 'C'), ('D', 'A')]
>>> filter(fun, dct.items())
[('A', 'C'), ('D', 'A')]
>>> filter(lambda tpl: wanted in tpl, dct.items())
[('A', 'C'), ('D', 'A')]
Convert list of tuples with 2 items into dictionary
>>> tpllst = [('A', 'C'), ('D', 'A')]
>>> dict(tpllst)
{'A': 'C', 'D': 'A'}
Function doing the work
Long version
This version is here to explain what is going on step by step:
def get_key_or_val_itms(dct, wanted):
# dict as [(key, val), (key2, val2), ...]
tpldct = dct.items()
# find tuples, where either key or val equals `wanted` value
# first make function, which detects, the tuple we search for
def tuple_wanted(tpl):
return wanted in tpl
# now use it to filter only what we search for
restpldct = filter(tuple_wanted, tpldct)
# finally, turn the result into dict
return dict(restpldct)
Short version
def get_key_or_val_itms(dct, wanted):
return dict(filter(lambda tpl: wanted in tpl, dct.items()))
Conclusions
It works (with either long or short version of the function):
>>> dct = {'A': 'C', 'R': 'E', 'D': 'A', 'L': 'R', 'C': 'D'}
>>> wanted = "A"
>>> get_key_or_val_itms(dct, wanted)
{'A': 'C', 'D': 'A'}
If you put the function into file with test suite, calling $ py.test -sv the_file.py shall output:
$ py.test -sv the_file.py
py.test================================ test session starts =========================
=======
platform linux2 -- Python 2.7.9, pytest-2.8.7, py-1.4.31, pluggy-0.3.1 -- /home/javl/
.virtualenvs/stack/bin/python2
cachedir: .cache
rootdir: /home/javl/sandbox/stack/dict, inifile:
collected 5 items
countdict.py::test_it[scenario0] PASSED
countdict.py::test_it[scenario1] PASSED
countdict.py::test_it[scenario2] PASSED
countdict.py::test_it[scenario3] PASSED
countdict.py::test_it[scenario4] PASSED
============================= 5 passed in 0.01 seconds ==============================
As can be seen, all the scenarios are passing.
Explanation how py.test works is out of scope of this answer, to learn more about it, see http://pytest.org/latest/
I wouldn't know how to avoid using a for loop, other than making your own for loop, similar to the following:
i = 0
def func(tup, id) {
if i < len(dictionary_items):
output = False
if tup[0] == id or tup[1] == id:
output = id + ' '
i += 1
return output
}
dictionary_items = dictionary.items()
func(dictionary_items[0], id)
func(dictionary_items[1], id)
func(dictionary_items[2], id)
And so on. However, that would be ugly and extremely non-pythonic.
As for making your code more pythonic, you can change the lines output = output + k + ' ' to output += k + ' ' or output = k + ' ' (You're concatenating strings k and ' ' to an empty string, output, which changes nothing about the strings k and ' ').
Furthermore, you could check if j == id or k == id rather than two seperate if statements, then saying output = id + ' ',since if j or k are equal to id, it doesn't matter if you return whichever of j and k is equal to the id or if you return the id itself.
You have to check all the keys and values, so there is always going to be some type of loop. Python has many ways to iterate (ie. loop) through items without explicit use of for.
One good way to iterate through items without for is with the filter, map, and reduce built-in functions along with the lambda syntax for creating small, anonymous functions.
from itertools import chain
# Get values for matching keys and vice versa
values = map(lambda x: x[1] if x[0] == id else None, dct.items())
keys = map(lambda x: x[0] if x[1] == id else None, dct.items())
# Then you filter out the None values
# itertools.chain allows us to conveniently do this in one line
matches = filter(lambda x: x is not None, chain(keys, values))
If you can't use itertools.chain, you'll just need a few extra steps
keys = filter(lambda x: x is not None, keys)
values = filter(lambda x: x is not None, values)
matches = keys + values
If you need a space separated output of values:
output = ' '.join(matches)
You could use list comprehensions, although one could argue that it is a kind of for loop:
example_dictionary = {'A': 'C', 'R': 'E', 'D': 'A', 'L': 'R', 'C': 'D'}
def get_interactions(dic, id):
output =[v for k, v in dic.items() if k == id] + [k for k,v in dic.items() if v == id]
return output
I have a following dictionary:
d1 = {}
I need to assign it the following values, but only the first n values from the following list:
all_examples= ['A,1,1', 'B,2,1', 'C,4,4', 'D,4,5']
Final output: d1={"A":[1,1],"B":[2,1]}
1st version of the Question:
I have a following dictionary:
d1 = {'UID': 'A12B4', 'name': 'John', 'email': 'hi#example.com'}
How do I create a dictionary d2 such that d2 has the first n number of keys and values from d1?
2nd version of the Question
I have a following dictionary:
d1 = {}
I need to assign it the following values, but only the first n values from the following list:
all_examples= ['A,1,1', 'B,2,1', 'C,4,4', 'D,4,5']
How do I create a dictionary d2 such that d2 has the first n number of keys and values from d1?
I'm sorry to tell you, but you shouldn't do that. At least, not with the stock dict. The reason is that no order is guaranteed in a dict, and whenever you'll add or remove a value, the order of the dict CAN change.
But if you really insist you could do:
>>> d1 = {1:'a', 3:'b', 2:'c', 4:'d'}
>>> d1
{1: 'a', 2: 'c', 3: 'b', 4: 'd'}
>>> d.keys()[:2]
[1, 2]
>>> {k : d[k] for k in d.keys()[:2]}
{1: 'a', 2: 'c'}
but my suggestion to you is to use an OrderedDict object, that will guarantee the order of the elements within the dict:
>>> od = OrderedDict()
>>> od[1] = 'a'
>>> od[3] = 'b'
>>> od[2] = 'c'
>>> od[4] = 'd'
>>> od
OrderedDict([(1, 'a'), (3, 'b'), (2, 'c'), (4, 'd')])
>>> od.keys()[:2]
[1, 3]
>>> OrderedDict([(k, od[k]) for k in od.keys()[:2]])
OrderedDict([(1, 'a'), (3, 'b')])
Ok, looks like you just changed radically your question, so here's the new answer:
>>> all_examples= ['A,1,1', 'B,2,1', 'C,4,4', 'D,4,5']
>>> n = 2
>>> all_examples[:n]
['A,1,1', 'B,2,1']
here's how you select up to n values of a list.
once again, you're changing your question…
Final output: d1={"A":[1,1],"B":[2,1]}
well you can just do:
>>> {elt[0] : (elt[1], elt[2]) for elt in [elt.split(',') for elt in all_examples[:n]]}
{'A': ('1', '1'), 'B': ('2', '1')}
HTH
I have a list as a input made from tuples where the origin is the 1st object and the neighbour is the 2nd object of the tuple.
for example :
inp : lst = [('a','b'),('b','a'),('c',''),('a','c')]
out : {'a': ('a', ['b', 'c']), 'b': ('b', ['a']), 'c': ('c', [])}
first i tried to cast the list into a dictonary,
like this
dictonary = dict(lst)
but i got an error say that
dictionary update sequence element #0 has length 1; 2 is required
The simplest is probably inside a try / except block:
lst = [('a','b'),('b','a'),('c',''),('a','c')]
out = dict()
for k, v in lst:
try:
if v != '':
out[k][1].append(v)
else:
out[k][1].append([])
except KeyError:
if v != '':
out[k] = (k, [v])
else:
out[k] = (k, [])
print out
Which gives:
{'a': ('a', ['b', 'c']), 'b': ('b', ['a']), 'c': ('c', [])}
Here's how I did it, gets the result you want, you can blend the two operations into the same loop, make a function out of it etc, have fun! Written without Python one liners kung-fu for beginner friendliness!
>>> lst = [('a','b'),('b','a'),('c',''),('a','c')]
>>> out = {}
>>> for pair in lst:
... if pair[0] not in out:
... out[pair[0]] = (pair[0], [])
...
>>> out
{'a': ('a', []), 'c': ('c', []), 'b': ('b', [])}
>>> for pair in lst:
... out[pair[0]][1].append(pair[1])
...
>>> out
{'a': ('a', ['b', 'c']), 'c': ('c', ['']), 'b': ('b', ['a'])}
Just here to mention setdefault
lst = [('a','b'),('b','a'),('c',''),('a','c')]
d = {}
for first, second in lst:
tup = d.setdefault(first, (first, []))
if second and second not in tup[1]:
tup[1].append(second)
I have data stored in a list of lists organized like so:
lst = [
['FHControl', G, A]
['MNHDosed', G, C]
]
For row in lst: row[0] there are a total of 12 categories (I've listed two in the sample code above). For row[1] and row[2] I am only concerned with 6 of the combinations of these letters. Therefore, I have 72 possible combinations of this data per row in lst and need to count the instances of each combination without having to write dozens of nested if loops.
I am attempting in creating two functions to parse through these lists and bin the incidences of these 72 combinations. How can I use two function like what I am beginning to write below to update these variables? Do I need to construct the dictionaries as class variables so that I can continue to update them as I iterate through both functions? Any guidance would be great!
Here is the code I have currently that initializes all 72 variables into 6 dictionaries (for the 6 combinations of letters in row[1] and row[2]):
def baseparser(lst):
TEMP = dict.fromkeys('FHDosed FHControl FNHDosed FNHControl '
'FTDosed FTControl MHDosed MHControl '
'MNHDosed MNHControl MTDosed MTControl'.split(), 0)
TRI_1, TRI_2, TRV_1, TRV_2, TRV_3, TRV_4 = ([dict(TEMP) for i in range(6)])
for row in lst:
if row[0] == 'FHDosed':
binner(row[0], row[1], row[2])
if row[0] == 'FHControl':
binner(row[0], row[1], row[2])
etc.
def binner(key, q, s):
if (q == 'G' and s == 'A') or (q =='C' and s =='T'):
TRI_1[key] += 1
elif (q == 'A' and s == 'G') or (q =='T' and s =='C'):
TRI_2[key] += 1
elif (q == 'G' and s == 'T') or (q =='C' and s =='A'):
TRV_1[key] += 1
elif (q == 'G' and s == 'C') or (q =='C' and s =='G'):
TRV_1[key] += 1
elif (q == 'A' and s == 'T') or (q =='T' and s =='A'):
TRV_1[key] += 1
elif (q == 'A' and s == 'C') or (q =='T' and s =='G'):
TRV_1[key] += 1
Your code could be simplified to:
TEMP = dict.fromkeys('''FHDosed FHControl FNHDosed FNHControl FTDosed FTControl MHDosed
MHControl MNHDosed MNHControl MTDosed MTControl'''.split(), 0)
TRI_1, TRI_2, TRV_1, TRV_2, TRV_3, TRV_4 = [TEMP.copy() for i in range(6)]
dmap = {
('G', 'A'): TRI_1,
('C', 'T'): TRI_1,
('A', 'G'): TRI_2,
('T', 'C'): TRI_2,
('G', 'C'): TRV_1,
('C', 'G'): TRV_1,
('A', 'T'): TRV_1,
('T', 'A'): TRV_1,
}
for row in lst:
key, q, s = row
dmap[q, s][key] += 1
Another possiblity is to use one dict of dicts instead of 6 dicts:
TEMP = dict.fromkeys('''FHDosed FHControl FNHDosed FNHControl FTDosed FTControl MHDosed
MHControl MNHDosed MNHControl MTDosed MTControl'''.split(), 0)
TR = {key:TEMP.copy() for key in ('TRI_1', 'TRI_2', 'TRV_1', 'TRV_2', 'TRV_3', 'TRV_4')}
dmap = {
('G', 'A'): 'TRI_1',
('C', 'T'): 'TRI_1',
('A', 'G'): 'TRI_2',
('T', 'C'): 'TRI_2',
('G', 'C'): 'TRV_1',
('C', 'G'): 'TRV_1',
('A', 'T'): 'TRV_1',
('T', 'A'): 'TRV_1',
}
lst = [
['FHControl', 'G', 'A'],
['MNHDosed', 'G', 'C']
]
for row in lst:
key, q, s = row
TR[dmap[q, s]][key] += 1
print(TR)
The advantage of doing it this way is that you have fewer dicts in your namespace, and it may be easier to refactor the code later using a dict of dicts instead of hard-coding 6 dicts.
Following up on Midnighter's suggestion, if you have pandas, you could replace the dict of dicts with a DataFrame. Then the frequency of pairs could be computed using pd.crosstabs like this:
import pandas as pd
dmap = {
'GA': 'TRI_1',
'CT': 'TRI_1',
'AG': 'TRI_2',
'TC': 'TRI_2',
'GC': 'TRV_1',
'CG': 'TRV_1',
'AT': 'TRV_1',
'TA': 'TRV_1',
}
lst = [
['FHControl', 'G', 'A'],
['MNHDosed', 'G', 'C']
]
df = pd.DataFrame(lst, columns=['key', 'q', 's'])
df['tr'] = (df['q']+df['s']).map(dmap)
print(df)
# key q s tr
# 0 FHControl G A TRI_1
# 1 MNHDosed G C TRV_1
print(pd.crosstab(rows=[df['key']], cols=[df['tr']]))
yields
tr TRI_1 TRV_1
key
FHControl 1 0
MNHDosed 0 1
I'm new to this site, and I have a problem that I need some help with. I am trying to find the highest integer value in a dictionary and the corresponding key and then check if there are other keys with the same value. If there are duplicate values i want to randomly select one of them and return it. As of now the code can find the highest value in the dictionary and return the key, but it returns the same key each time. I'm not able to check for other keys with the same value.
def lvl2():
global aiMove2
posValueD = {}
for x in moveList(): #Movelist returns a list of tuples
m = aiFlip(x) #aiFlip returns an integer
posValueD[x] = m
aiMove2 = max(posValueD, key = posValueD.get)
return aiMove2
After getting the maximum, you can check each key of their values. This comprehension list returns a list of keys where the value associated if the same as aiMove2.
keys = [x for x,y in posValueD.items() if y == posValueD[aiMove2]]
Here's an example in Python shell:
>>> a = {'a':1, 'b':2, 'c':2}
>>> [x for x,y in a.items() if y == 2]
['c', 'b']
You could write something like this:
max_value = 0
max_keys = []
for key,value in myDict.iteritems():
if value > max_value:
max_value = value
max_keys = [key]
elif value == max_value:
max_keys.append(key)
if max_keys:
return random.choice(max_keys)
return None
You could use itertools groupby:
from itertools import groupby
di={'e': 0, 'd': 1, 'g': 2, 'f': 0, 'a': 1, 'c': 3, 'b': 2, 'l': 2, 'i': 1, 'h': 3, 'k': 0, 'j': 1}
groups=[]
for k, g in groupby(sorted(di.items(), key=lambda t: (-t[1], t[0])), lambda t: t[1]):
groups.append(list(g))
print(groups)
# [[('c', 3), ('h', 3)],
[('b', 2), ('g', 2), ('l', 2)],
[('a', 1), ('d', 1), ('i', 1), ('j', 1)],
[('e', 0), ('f', 0), ('k', 0)]]
Or, more succinctly:
print([list(g) for k, g in groupby(
sorted(di.items(), key=lambda t: (-t[1], t[0])),
lambda t: t[1])])
Then just take the first list in the groups list of lists.