End Goal to create the following Dictionary
DictFinal = {'peach': [7,33], 'berries': [33,47], 'grapes': [47,98], 'apple': [98,200]}
snippets of code
FinalEndofline = 200
List1 = ["apple","peach","grapes","berries"]
List2 = [98,7,47,33]
Step1 : To create a dictionary using key value.List1 is the key and List2 is value.
professions_dict = dict(zip(List1, List2))
print professions_dict
Output - {'apple': 98, 'peach': 7, 'grapes': 47, 'berries': 33}
Step 2 : Sort the dictionary based on value
sorted_x = sorted(professions_dict.items(), key=operator.itemgetter(1))
print sorted_x
Output - {'peach': 7, 'berries': 33, 'grapes': 47, 'apple': 98}
Step 3 : Now how do I achieve
DictFinal = {'peach': [7,33], 'berries': [33,47], 'grapes': [47,98], 'apple': [98,200]}
The Dictfinal is again a key value, but a value having the list with first value and second value and goes on and it appends the finalendofline variable to last value list
>>> List1 = ["apple","peach","grapes","berries"]
>>> List2 = [98,7,47,33]
>>> List1 = [x[1] for x in sorted(zip(List2, List1))]
>>> List2.sort()
>>> List2.append(200)
>>> DictFinal = dict((key, List2[i:i+2]) for i, key in enumerate(List1))
>>> DictFinal
{'berries': [33, 47], 'grapes': [47, 98], 'peach': [7, 33], 'apple': [98, 200]}
That's fairly straightforward. This is probably a bit more efficient, though -- only requires one sort(). If efficiency really matters, you could also use itertools to do the slice on the second zip (and, of course, with Python 2, you would want to use izip instead of zip).
>>> List1 = ["apple","peach","grapes","berries"]
>>> List2 = [98,7,47,33]
>>> zipped = sorted(zip(List2, List1)) + [(200,)]
>>> FinalDict = dict((x[1], [x[0], y[0]]) for x, y in zip(zipped, zipped[1:]))
Maybe try:
List2 = ["""Blah""",FinalEndofLine]
unsorted = dict(zip(List1,[[List2[i],List2[i+1]] for i in range(len(l2) - 1)]))
DictFinal = sorted(unsorted.items(), key = lambda x: x[1][0])
This seemed to work for me, if I understand your problem fully. List2 just needs that FinalEndofLine at the end.
Related
I have an iterable of unique numbers:
lst = [14, 11, 8, 55]
where every value is somewhere among numbers of dict's iterable-values, say lists:
dict_itms.items() = dict_items([(1, [0, 1, 2, 3]), (2, [11, 14, 12]), (3, [30, 8, 42]), (4, [55, 6])])
I have to find each lst element in a dict such a way that, finally, I would have a list of keys pairwise against each element in lst.
This method:
keys_ = []
for a in lst:
for k, v in dict_itms.items():
if a in v:
keys_ += [k]
break
else:
continue
gives:
[2, 2, 3, 4]
Is there more efficient way to find every key pairwise against each number to find?
You can use any in a list comprehension:
print([k for k,v in dict_itms.items() if any(x in lst for x in v)])
Output:
[2, 3, 4]
Update
According to this answer not set(v).isdisjoint(lst) is the fastest:
print([k for k,v in dict_itms.items() if not set(v).isdisjoint(lst)])
It's unclear what you mean by 'efficient'; do you need this to be efficient in a given pass or in aggregate? The reason I ask is that typically the best way to handle this in aggregate is by doing a pre-processing pass that flips your key-value relation:
reverse_lookup = dict()
for k,v in d.items():
for i in v:
keys = reverse_lookup.get(i, []) # Provide an empty list if this item not yet found
keys.append(k)
reverse_lookup[i] = keys
Now that you have your reverse lookup processed, you can use it in a straightforward manner:
result = [reverse_lookup.get(i) for i in lst]
# `result` is actually a list of lists, so as to allow duplicates. You will need to flatten it, or change the reverse lookup to ignore dupes.
The initial processing for the reverse lookup is O(n*m), where n*m is the total length of the original dictionary values summed. However, each lookup for the lst portion is O(1), so if you squint and have enough lookups this is O(p), where p is the length of lst. This will be wildly more efficient than other approaches if you have to do it a lot, and much less efficient if you're only ever passing over a given dictionary once.
A simple and Pythonic implementation:
d = dict([(1, [0, 1, 2, 3]), (2, [11, 14, 12]), (3, [30, 8, 42]), (4, [55, 6])])
xs = [14, 11, 8, 55]
keys = [k for k, v in d.items() if set(v).intersection(xs)]
print(keys)
However, this doesn't duplicate the 2 key, which your example does - not sure if that's behaviour you need?
I'm trying to count the tot values of sub dictionaries with same subkeys. I have a list containing the relevant keys mylist, I only need to count the total of the values for each element in the list.
mylist = ['age','answ1', 'answ2', 'answ3']
d = {'01': {'age':19, 'answ1':3, 'answ2':7, 'answ3':2}, '02': {'age':52, 'answ1':8, 'answ2':1, 'answ3':10},...}
I've tried
tot = []
for k,v in d.items():
for ke, va in v.items():
for i in mylist[0:]
count=0
if ke == i:
count+=v[ke]
tot.append(count)
but instead of the sum of the values with same key, I get the values of different keys in the order of appearance in the dictionary.
The expected outcome would be
tot = [71, 11, 8, 12]
What I get is
tot = [19, 3, 7, 2, 52, 8, 1, 10]
With collections.Counter:
>>> ctr = sum(map(Counter, d.values()), Counter())
>>> [ctr[x] for x in mylist]
[71, 11, 8, 12]
Or:
>>> [sum(e[k] for e in d.values()) for k in mylist]
[71, 11, 8, 12]
In case some sub dicts can have keys missing, just use e.get(k, 0). The Counter solution doesn't need it, it supplies zeros by default.
Hmm, since you now accepted a dict result solution...
>>> dict(sum(map(Counter, d.values()), Counter()))
{'age': 71, 'answ1': 11, 'answ2': 8, 'answ3': 12}
Or maybe just
>>> sum(map(Counter, d.values()), Counter())
Counter({'age': 71, 'answ3': 12, 'answ1': 11, 'answ2': 8})
Although these might have more keys than just the desired ones, if there are more in your data.
If you wish to store your result in a dictionary, you can create one with the keys from your list and calculate the results there.
result = {i: 0 for i in mylist}
for k, v in d.items():
result['age'] += v['age']
result['answ1'] += v['answ1']
result['answ2'] += v['answ2']
result['answ3'] += v['answ3']
result
{'age': 71, 'answ1': 11, 'answ2': 8, 'answ3': 12}
However this does rely on the keys not changing, order should not matter.
EDIT
You can do this regardless of key names with the following update. Note it adds one extra iteration.
result = {i: 0 for i in mylist}
for k, v in d.items():
for ke, va in v.items():
result[ke] += v[ke]
mylist = ['age','answ1', 'answ2', 'answ3']
d = {'01': {'age':19, 'answ1':3, 'answ2':7, 'answ3':2}, '02': {'age':52, 'answ1':8, 'answ2':1, 'answ3':10}}
tot = [0] * len(mylist)
for k in d:
for idx, i in enumerate(mylist):
tot[idx] += d[k].get(i, 0)
print(tot)
Prints:
[71, 11, 8, 12]
Try the following code
for i in mylist:
count=0
for k,v in d.items():
for ke, va in v.items():
if ke == i:
count+=va
tot.append(count)
~
You can accomplish this using list comprehensions, zip and map. Firstly, we want to extract the corresponding values from each sub-dict:
>>> vals = [[v[k] for k in mylist] for v in d.values()]
>>> vals
[[19, 3, 7, 2], [52, 8, 1, 10]]
Now we want to perform an element-wise sum across all the sub-lists:
>>> result = map(sum, zip(*vals))
>>> list(result)
[71, 11, 8, 12]
Putting it all in one line:
>>> result = map(sum, zip(*([v[k] for k in mylist] for v in d.values())))
>>> list(result)
[71, 11, 8, 12]
This approach has the benefit of only accessing the keys that we want to build instead of constructing a full Counter and then afterwards extracting the data.
Same thing but different.
>>> import operator
>>> f = operator.itemgetter(*mylist)
>>> vals = map(f,d.values())
>>> sums = map(sum,zip(*vals))
>>> result = dict(zip(mylist,sums))
>>> result
{'age': 71, 'answ1': 11, 'answ2': 8, 'answ3': 12}
If you don't want the dict, skip that and use result = list(sums)
Suppose
List1 = [ 23, 45, 6, 7, 34]
List2 = [46, 23, 1, 14, 68, 56]
Compare List1 and List2 and print the element of List1 which have a double value in List2
Output = [23,7,34]
Try this:
Output = [i for i in List1 if i*2 in List2]
You can convert list2 to a set for efficient lookups, and use a list comprehension with the said condition for the desired output:
set2 = set(List2)
[i for i in List1 if i * 2 in set2]
You already have the answer but just of the sake of simplicity. Basically you want to iterate through List1 and check if double value is in List2. If so add element to the output array.
List1 = [ 23, 45, 6, 7, 34]
List2 = [46, 23, 1, 7, 14, 68, 56]
output = []
for i in List1:
if i*2 in List2:
output.append(i)
print output
You already got the answers. However, just for fun, I came up with the following method. I did not benchmark all the approaches listed here. It can be fun to do that. This is an interesting question and can be investigated more. However, just for the sake of it I present the solution I did.
import numpy as np
l = np.array(List1) * 2
print(l)
## array([46, 90, 12, 14, 68])
print(set(l) & set(List2))
## {68, 46, 14}
l2 = set(l) & set(List2)
print([List1[list(np.nonzero(l == i))[0][0]] for i in l if i in l2])
## [23, 7, 34]
It uses the broadcasting of numpy along with the fast intersection operation of Python set. This maybe useful if the two lists are very big.
I have a dictionary
{1:’one’,2:’two’}
I want to reverse it using a function and became to the following
{‘1:’eno’,2:’owt’ }
How can I do it?
Similarly, if I have a list or tuple like [15,49], how can I convert it to [94,51]?
You can use a simple dict comprehension, using the fact that string[::-1] reverses a string:
>>> d = {1: "one", 2: "two"}
>>> {x: v[::-1] for x, v in d.items()}
{1: 'eno', 2: 'owt'}
You could also define a function:
def reverse_values(dct):
for key in dct:
dct[key] = dct[key][::-1]
Which will alter the values in the same dict.
>>> reverse_values(d)
>>> d
{1: 'eno', 2: 'owt'}
For converting list of type [15,49] to [94, 51], you can try the snippet below (this will work for lists of type [12, 34, 56, 78] to [87, 65, 43, 21] as well):
>>> l = [15,49]
>>> [int(str(x)[::-1]) for x in l[::-1]]
[94, 51]
For your question here, use the following:
Given that [::-1] reverses the string, we can convert each number to a string, reverse each item, convert back to an integer, then reverse the entire list:
>>> lst = [15, 49]
>>> [int(str(item)[::-1]) for item in lst][::-1]
[94, 51]
>>>
I don't wan to use numpy to work with a 2D matrix
I figured out how to create something that looks like a row and column dictionary. It works fine if I want to look up single values.
But I'm having trouble figuring out how to get values from a row in the same order as I use my columns
from collections import defaultdict
dic = defaultdict(dict)
rowKeys = ['1','2','3']
columnKeys = ['alfa', 'omega', 'bravo', 'charlie']
# Filling up the dictionary with values
from random import randrange
for rKey in rowKeys:
for cKey in columnKeys:
dic[rKey][cKey] = randrange(50)
"""
print dic
defaultdict(<type 'dict'>, {
'1': {'omega': 28, 'charlie': 42, 'alfa': 13, 'bravo': 45},
'3': {'omega': 8, 'charlie': 5, 'alfa': 13, 'bravo': 4},
'2': {'omega': 19, 'charlie': 42, 'alfa': 29, 'bravo': 26}})
"""
# print dic[rowKeys[0]].keys()
# ['omega', 'charlie', 'alfa', 'bravo']
# In [28]: print dic[rowKeys[0]].values()
# [28, 42, 13, 45]
I want a list of values in the "original" order
[13, 28, 45, 42]
Is there a clean easy-to-read way of doing this?
UPDATE
#jamylak came with an answer that solved my specific problem.
But it did not truly answer my question of how to get values by a list. Suppose I change the order of columnKeys alphabetically (or by other non-logic order) and want to get at list of values returned in that order.
How would I go about that __?
from collections import defaultdict, OrderedDict
dic = defaultdict(OrderedDict)
rowKeys = ['1','2','3']
columnKeys = ['alfa', 'omega', 'bravo', 'charlie']
# Filling up the dictionary with values
from random import randrange
for rKey in rowKeys:
for cKey in columnKeys:
dic[rKey][cKey] = randrange(50)
clean and easy-to-read way would be using list comprehensions.
def readdict(D, rowkeys=(1, 2, 3)):
def readcol(d, columnKeys=('alfa', 'omega', 'bravo', 'charlie')):
return [d[key] for key in columnKeys]
return [readcol(D[key]) for key in rowkeys]
'''outputs :
[[13, 28, 45, 42],
[29, 19, 26, 42],
[13, 8, 4, 5]]'''
for row in dic.values(): #get each row 'dict'
for k,v in sorted(row.items(),key=lambda k: columnKeys.index(k[0])): #sort base on index of key occurring in columnKeys
print(k,v)
Would output for example:
('alfa', 43)
('omega', 30)
('bravo', 24)
('charlie', 2)
For {'omega': 29, 'charlie': 11, 'alfa': 4, 'bravo': 3}
myDict = {'k42':'cat', 'k5':'fish', 'k1':'bird', 'k9':'dog'}
keyList = ['k1', 'k42', 'k9', 'k5']
outList = [myDict[x] for x in keyList]