python dictionary with list as values - python

I have a list of string like
vals = ['a', 'b', 'c', 'd',........]
using vals, I would be making a request to a server with each vals[i]. The server would return me a number for each of the vals.
it could be 1 for 'a', 2 for 'b', 1 again for 'c', 2 again for 'd', and so on.
Now I want to create a dictionary that should look like
{ 1: ['a','c'], 2:['b','d'], 3: ['e'], ..... }
What is the quickest possible way to achieve this? Could I use map() somehow?
I mean I can try doing this by storing the results of request in a separate list and then map them one by one - but I am trying to avoid that.

The following should work, using dict.setdefault():
results = {}
for val in vals:
i = some_request_to_server(val)
results.setdefault(i, []).append(val)
results.setdefault(i, []).append(val) is equivalent in behavior to the following code:
if i in results:
results[i].append(val)
else:
results[i] = [val]

Alternatively, you can use defaultdict from collections like so:
from collections import defaultdict
results = defaultdict(list)
for val in vals:
i = some_request_to_server(val)
results[i].append(val)

Related

Python dictionary with multiple unique values corresponding to a key

I have 2 lists which correspond to what I would like to be my key:value pairs, for example:
list_1 = [1,1,1,1,1,1,1,1,1,2,2,2,2,2,2] #(key)
list_2 = [x,x,x,y,g,r,t,w,r,r,r,t,f,c,d] #(value)
I've (kind of) been able to create a dictionary via: dict = dict(zip(list_1, [list_2]))
However the problem with this is that it is only picking up '1' as a key and also results in duplicate entries within the list of values for the key.
Can anyone suggest a way to create a dictionary so that only the unique values from list_2 are mapped to their corresponding key?
Thanks
EDIT:
output I'm looking for would be one dictionary keyed by 1 and 2 with lists as values containing only the unique values for each i.e.:
dict = {1: [x,y,g,r,t,w], 2: [r,t,f,c,d]}
This sort of problem is properly solved with a collections.defaultdict(set); the defaultdict gives you easy auto-vivificaction of sets for each key on demand, and the set uniquifies the values associated with each key:
from collections import defaultdict
mydict = defaultdict(set)
for k, v in zip(list_1, list_2):
mydict[k].add(v)
You can then convert the result to a plain dict with list values with:
mydict = {k: list(v) for k, v in mydict.items()}
If order of the values must be preserved, on modern Python you can use dicts instead of set (on older Python, you'd use collections.OrderedDict):
mydict = defaultdict(dict)
for k, v in zip(list_1, list_2):
mydict[k][v] = True # Dummy value; we're using a dict to get an ordered set of the keys
with the conversion to plain dict with list values being unchanged
If the input is already sorted, itertools.groupby is theoretically slightly more efficient (it's actual O(n), vs. average case O(n) using dicts), but in practice the defaultdict is typically as faster or faster (the implementation of groupby has some unavoidable inefficiencies). Just for illustration, the groupby solution would be:
from itertools import groupby
from operator import itemgetter
mydict = {k: {v for _, v in grp} for k, grp in groupby(zip(list_1, list_2), key=itemgetter(0))]
# Or preserving order of insertion:
getval = itemgetter(1) # Construct once to avoid repeated construction
mydict = {k: list(dict.fromkeys(map(getval, grp)))
for k, grp in groupby(zip(list_1, list_2), key=itemgetter(0))]
Since a dictionary is a set it cant contain twice the same key but it can have the key once then a list of value for that you can use the one-line method
my_dict = {key:[list_2[i] for i in range(len(list_2)) if list_1[i]==key] for key in set(list_1)}
Or a more classic method
my_dict = {}
for key_id in range(len(list_1)):
if list_1[key_id] not in my_dict:
my_dict[list_1[key_id]] = []
my_dict[list_1[key_id]].append(list_2[key_id])
In both case the result is
my_dict = {1: ['x', 'x', 'x', 'y', 'g', 'r', 't', 'w', 'r'], 2: ['r', 'r', 't', 'f', 'c', 'd']}
The problem is your key is too unique. there're only two unique keys 1 and 2. So if you're creating dictionaries you can't have {1:x, 1:y} at same time for example, unless you change the key to something new and unique.
I would use a tuple in your purpose:
list(set(tuple(zip(list_1, list_2))))
The set gives you unique mappings which is what dropping the duplicates.
keys = [1,1,1,1,1,1,1,1,1,2,2,2,2,2,2]
values = ['x','x','x','y','g','r','t','w','r','r','r','t','f','c','d']
result = {}
for key,value in zip(keys,values):
if key not in result:
result[key] = []
if value not in result[key]:
result[key].append(value)
else:
if value not in result[key]:
result[key].append(value)
print(result)
{1: ['x', 'y', 'g', 'r', 't', 'w'], 2: ['r', 't', 'f', 'c', 'd']}
Note:
zip(keys,values) this will create a iterable of tuples, each tuple consist of one element from the keys and values.
(1,'x')
(1,'x')

How to call each value of a dictionary by its key?

I want to separate each (key, value) pair from a dictionary and want to call each value by its key name.
I have two lists,
1. ListA = [1, 2, 3, 4, 5]
2. ListB = ['A', 'B', 'C', 'D', 'E']
Now I have created a dictionary like this,
Dict = {1: 'A', 2: 'B', 3: 'C', 4: 'D', 5: 'E'}
So, now if I want to see value for each key, I have to type:
Dict[key].
Now I expect my result to be like:
If I ask for the value of each key, I have to just type key not Dict[key]
and it should give me the answer.
Typing 1 should give A.
Typing 2 should give B.
You can somehow do like this but you if you can simply access below is not a very good idea honestly. You can set key as attribute of an object.
But it wont work for the dictionary you have my Input Dictionary is {"key1":"Apple"}
class MyDict:
def __init__(self,input_dict):
for key,value in input_dict.items():
setattr(self,key,value) #setting key as attribute
obj = MyDict({"key1":"Apple"}) #new instance
print(obj.key1) # this will print Apple
But still it wont work like obj.1 better not to mess it.
If you want to loop over dictionary values, you can use Dict.values():
for v in Dict.values():
print(v)
# > 'A'
# > 'B'
# ...
Inside a while true loop, keep popping items from your lists until you run into an IndexError like this:
ListA = [1, 2, 3]
ListB = ['A', 'B', 'C']
DictC = {}
while True:
try:
DictC[ListA.pop(0)] = ListB.pop(0)
except IndexError:
break
print(DictC)

creating a dictionary using two lists (no zip) PYTHON

I am trying to create a dictionary using two lists without the use of zip. can someone help me to finish the code. The function should return an empty dictionary if the lists were empty.
key_list=[1,2,3,4]
value_list=['a','b','c','d']
def list_to_dict(key_list,value_list):
new_dict={}
if len(key_list)!=0 and len(value_list)!=0:
for i in range(len(key_list)):
dict[key_list[i]]=value_list[i]
return new_dict
the output I want is
new_dict={1:'a', 2:'b', 3:'c', 4:'d'}
Your return should go outside the for loop scope, also check for the min lenght of both lists:
def list_to_dict(key_list,value_list):
new_dict = {}
if len(key_list) != 0 and len(value_list) != 0:
for i in range(min(len(key_list), len(value_list))):
new_dict[key_list[i]] = value_list[i]
return new_dict
key_list=[1,2,3,4]
value_list=['a','b','c','d']
def list_to_dict(key_list,value_list):
new_dict={}
if len(key_list)!=0 and len(value_list)!=0 and len(key_list) == len(value_list):
for key, index in enumerate(key_list):
dict[key]=value_list[index]
return new_dict
You had an error in your indentation. Also, both lists need to be the same length to avoid an error, so I added that check. For extra learning, look up enumerate. GL on the rest of your homework :)
Try this.
key_list=[1,2,3,4]
value_list=['a','b','c','d']
def list_to_dict(key_list,value_list):
new_dict={}
if len(key_list)!=0 and len(value_list)!=0:
for i in range(len(key_list)):
new_dict[key_list[i]]=value_list[i]
return new_dict
key_list=[1,2,3,4]
value_list=['a','b','c','d']
def list_to_dict(key_list,value_list):
"""using dict comprehension, creating new key-value pair
for each key present in key list againt the value present in the value list."""
new_dict={key_list[i]:value_list[i] for i in range(len(key_list))}
return new_dict
result = list_to_dict(key_list,value_list)
print(result)
output
{1: 'a', 2: 'b', 3: 'c', 4: 'd'}
You can use a dict comprehension:
key_list = [1, 2, 3, 4]
value_list=['a', 'b', 'c', 'd']
def list_to_dict(key_list, value_list):
assert len(key_list) == len(value_list), "Both input lists should have equal length"
return {key_list[i]: value_list[i] for i in range(len(key_list))}
key_list = [1, 2, 3, 4]
value_list=['a', 'b', 'c', 'd']
my_dict={}
def list_dict(key_list,value_list):
for i in range((len(key_list))-1):
my_dict[key_list[i]] = value_list[i] #using loop to add one by one
i=i+1
return my_dict
You can try this for your home work
list_dict(key_list,value_list)

Reformatting a dict where the values have a dict-like relationship

I have a defaultdict that looks like this:
d = { 'ID_001': ['A', 'A_part1', 'A_part2'],
'ID_002': ['A', 'A_part3'],
'ID_003': ['B', 'B_part1', 'B_part2', 'A', 'A_part4'],
'ID_004': ['C', 'C_part1', 'A', 'A_part5', 'B', 'B_part3']
}
Before I go any further, I have to say that A_part1 isn't the actual string -- the strings are really a bunch of alphanumeric characters; I represented it as such to show that A_part1 is text that is associated with A, if you see what I mean.)
Standing back and looking at it, what I really have is a dict where the values have their own key/value relationship, but that relationship exists only in the order they appear in, in the list.
I am attempting to end up with something like this:
['ID_001 A A_part1, A_part2',
'ID_002 A A_part3',
'ID_003 B B_part1 B_part2',
'ID_003 A A_part4',
'ID_004 C C_part1',
'ID_004 A A_part5',
'ID_004 B B_part3']
I have made a variety of attempts; I keep wanting to run through the dict's value, making note of the character in the first position (eg, the A), and collect values until I find a B or a C, then stop collecting. Then append what I have to a list that I have declared elsewhere. Ad nauseum.
I'm running into all sorts of problems, not the least of which is bloated code. I'm missing the ability to iterate through the value in a clean way. Invariably, I seem to run into index errors.
If anyone has any ideas/philosophy/comments I'd be grateful.
What about something like:
d = { 'ID_001': ['A', 'A_part1', 'A_part2'],
'ID_002': ['A', 'A_part3'],
'ID_003': ['B', 'B_part1', 'B_part2', 'A', 'A_part4'],
'ID_004': ['C', 'C_part1', 'A', 'A_part5', 'B', 'B_part3']
}
def is_key(s):
return s in ['A','B','C']
out = {}
for (k,v) in d.iteritems():
key = None
for e in v:
if is_key(e): key = e
else:
out_key = (k,key)
out[out_key] = out.get(out_key, []) + [e]
which generates:
{('ID_001', 'A'): ['A_part1', 'A_part2'],
('ID_002', 'A'): ['A_part3'],
('ID_003', 'A'): ['A_part4'],
('ID_003', 'B'): ['B_part1', 'B_part2'],
('ID_004', 'A'): ['A_part5'],
('ID_004', 'B'): ['B_part3'],
('ID_004', 'C'): ['C_part1']}
It's important that you update the is_key function to match your actual input.
Also, the variable names are far from optimal, but I'm not really sure what you're doing -- you should be able to (and should) give them more appropriate names.
May not be in the order you want, but no thanks for further headaches.
d = { 'ID_001': ['A', 'A_part1', 'A_part2'],
'ID_002': ['A', 'A_part3'],
'ID_003': ['B', 'B_part1', 'B_part2', 'A', 'A_part4'],
'ID_004': ['C', 'C_part1', 'A', 'A_part5', 'B', 'B_part3']
}
rst = []
for o in d:
t_d={}
for t_o in d[o]:
if not t_o[0] in t_d:
t_d[t_o[0]] = [t_o]
else: t_d[t_o[0]].append(t_o)
for t_o in t_d:
rst.append(' '.join([o,t_d[t_o][0],', '.join(t_d[t_o][1:])]))
print(rst)
https://ideone.com/FeBDLA
['ID_004 C C_part1', 'ID_004 A A_part5', 'ID_004 B B_part3', 'ID_003 A A_part4', 'ID_003 B B_part1, B_part2', 'ID_002 A A_part3', 'ID_001 A A_part1, A_part2']
Whenever you're trying to do something involving contiguous groups, you should think of itertools.groupby. You weren't very specific about what condition separates the groups, but if we take "the character in the first position" at face value:
from itertools import groupby
new_list = []
for key, sublist in sorted(d.items()):
for _, group in groupby(sublist, key=lambda x: x[0]):
new_list.append(' '.join([key] + list(group)))
produces
>>> for elem in new_list:
... print(elem)
...
ID_001 A A_part1 A_part2
ID_002 A A_part3
ID_003 B B_part1 B_part2
ID_003 A A_part4
ID_004 C C_part1
ID_004 A A_part5
ID_004 B B_part3

list to dictionary conversion with multiple values per key?

I have a Python list which holds pairs of key/value:
l = [[1, 'A'], [1, 'B'], [2, 'C']]
I want to convert the list into a dictionary, where multiple values per key would be aggregated into a tuple:
{1: ('A', 'B'), 2: ('C',)}
The iterative solution is trivial:
l = [[1, 'A'], [1, 'B'], [2, 'C']]
d = {}
for pair in l:
if pair[0] in d:
d[pair[0]] = d[pair[0]] + tuple(pair[1])
else:
d[pair[0]] = tuple(pair[1])
print(d)
{1: ('A', 'B'), 2: ('C',)}
Is there a more elegant, Pythonic solution for this task?
from collections import defaultdict
d1 = defaultdict(list)
for k, v in l:
d1[k].append(v)
d = dict((k, tuple(v)) for k, v in d1.items())
d contains now {1: ('A', 'B'), 2: ('C',)}
d1 is a temporary defaultdict with lists as values, which will be converted to tuples in the last line. This way you are appending to lists and not recreating tuples in the main loop.
Using lists instead of tuples as dict values:
l = [[1, 'A'], [1, 'B'], [2, 'C']]
d = {}
for key, val in l:
d.setdefault(key, []).append(val)
print(d)
Using a plain dictionary is often preferable over a defaultdict, in particular if you build it just once and then continue to read from it later in your code:
First, the plain dictionary is faster to build and access.
Second, and more importantly, the later read operations will error out if you try to access a key that doesn't exist, instead of silently creating that key. A plain dictionary lets you explicitly state when you want to create a key-value pair, while the defaultdict always implicitly creates them, on any kind of access.
This method is relatively efficient and quite compact:
reduce(lambda x, (k,v): x[k].append(v) or x, l, defaultdict(list))
In Python3 this becomes (making exports explicit):
dict(functools.reduce(lambda x, d: x[d[0]].append(d[1]) or x, l, collections.defaultdict(list)))
Note that reduce has moved to functools and that lambdas no longer accept tuples. This version still works in 2.6 and 2.7.
Are the keys already sorted in the input list? If that's the case, you have a functional solution:
import itertools
lst = [(1, 'A'), (1, 'B'), (2, 'C')]
dct = dict((key, tuple(v for (k, v) in pairs))
for (key, pairs) in itertools.groupby(lst, lambda pair: pair[0]))
print dct
# {1: ('A', 'B'), 2: ('C',)}
I had a list of values created as follows:
performance_data = driver.execute_script('return window.performance.getEntries()')
Then I had to store the data (name and duration) in a dictionary with multiple values:
dictionary = {}
for performance_data in range(3):
driver.get(self.base_url)
performance_data = driver.execute_script('return window.performance.getEntries()')
for result in performance_data:
key=result['name']
val=result['duration']
dictionary.setdefault(key, []).append(val)
print(dictionary)
My data was in a Pandas.DataFrame
myDict = dict()
for idin set(data['id'].values):
temp = data[data['id'] == id]
myDict[id] = temp['IP_addr'].to_list()
myDict
Gave me a Dict of the keys, ID, mappings to >= 1 IP_addr. The first IP_addr is Guaranteed. My code should work even if temp['IP_addr'].to_list() == []
{'fooboo_NaN': ['1.1.1.1', '8.8.8.8']}
My two coins for toss into that amazing discussion)
I've tried to wonder around one line solution with only standad libraries. Excuse me for the two excessive imports. Perhaps below code could solve the issue with satisfying quality (for the python3):
from functools import reduce
from collections import defaultdict
a = [1, 1, 2, 3, 1]
b = ['A', 'B', 'C', 'D', 'E']
c = zip(a, b)
print({**reduce(lambda d,e: d[e[0]].append(e[1]) or d, c, defaultdict(list))})

Categories

Resources