Listing all values from tuple key in dict - python

Suppose I have a dictionary with a tuple as key, such as the following:
d1 = {}
d1[(111,1)] = "value1111"
d1[(111,2)] = "value1112"
d1[(111,3)] = "value1113"
d1[(112,1)] = "value1121"
d1[(112,2)] = "value1122"
d1[(112,3)] = "value1123"
How can I get all the values for a given number in the first element of the tuple key? That is, for the 111, I want to obtain the following:
value1111
value1112
value1113
I've tried print(d1[(111,i)]) but it only returns one value, is there a simple way of doing this?
Thanks in advance.

Use list comprehension, this way:
[v for k,v in d1.items() if k[0]==111]
The condition if k[0]==111 means return only values of d1 whose key's first element is 111
You were also trying with print(d1[(111,i)],that will work if you have a control over the range and types of the second element of key's tuple, i.e:
>>> [d1[(111,i)] for i in range(1,4)]
['value1111', 'value1112', 'value1113']
In your example, we know that the i can only be from 1 to 3, hence range(1,4), but if you don't know what's the range of i and even what the type of i could be, then the list comprehension is your best friend here.
Of course, one can get the list of second element of key's tuple whose first element is 111 by doing so:
>>>my_filter = [k[1] for k in d1 if k[0]==111]
[2, 3, 1]
>>>my_list = [d1[(111,i) for i in my_filter]
['value1112', 'value1113', 'value1111']

A simple list comprehension will do the trick:
>>> [d1[tup] for tup in d1 if tup[0] == 111]
['value1112', 'value1113', 'value1111']
It says "for every key tup in the dictionary, give me the corresponding value if the key's first element is 111".

If you control how the dict is created and want to group by the first element of your tuples forget using tuples as keys and use a defaultdict appending to a list to handle repeated keys:
from collections import defaultdict
d1 = defaultdict(list)
d1[111].append("value1111")
d1[111].append( "value1112")
d1[111].append("value1113")
d1[112].append("value1121")
d1[112].append("value1122")
d1[112].apendd("value1123")
Then you can get all the values at once or index the list to pull the ith value:
In [17]: d1
Out[17]:
defaultdict(list,
{111: ['value1111', 'value1112', 'value1113'],
112: ['value1121', 'value1122']})
In [18]: d1[111]
Out[18]: ['value1111', 'value1112', 'value1113']
In [19]: d1[111][0]
Out[19]: 'value1111'
In [20]: d1[111][1]
Out[20]: 'value1112'

Honestly, I think the default dict approach is the most flexible and allows you to query other values easily (e.g. 112 or 113). In the code below, d2 will be a map from the 111, 112, 113 to their respective values.
d2 = defaultdict(list)
for key, value in d1.iteritems():
d2[key[0]].append(value)
print d2[111]
print d2[112]

Related

How to sort a list containing frozensets (python)

I have a list of frozensets that I'd like to sort, Each of the frozensets contains a single integer value that results from an intersection operation between two sets:
k = frozenset(w) & frozenset(string.digits)
d[k] = w # w is the value
list(d) # sorted(d) doesn't work since the keys are sets and sets are unordered.
Here is the printed list:
[frozenset({'2'}), frozenset({'1'}), frozenset({'4'}), frozenset({'3'})]
How can I sort the list using the values contained in the sets?
You need to provide function as key to sorted which would accept frozenset as argument and return something which might be compared. If each frozenset has exactly 1 element and said element is always single digit then you might use max function (it will extract that single element, as sole element is always biggest element of frozenset) that is
d1 = [frozenset({'2'}), frozenset({'1'}), frozenset({'4'}), frozenset({'3'})]
d2 = sorted(d1,key=max)
print(d2)
output
[frozenset({'1'}), frozenset({'2'}), frozenset({'3'}), frozenset({'4'})]
If you want to know more read Sorting HOW TO
Previous answers can not sorted correctly, Because of strings
d = [frozenset({'224'}), frozenset({'346'}), frozenset({'2'}), frozenset({'22345'})]
sorted(d, key=lambda x: int(list(x)[0]))
Output:
[frozenset({'2'}),
frozenset({'224'}),
frozenset({'346'}),
frozenset({'22345'})]
Honestly, unless you really need to keep the elements as frozenset, the best might be to generate a list of values upstream ([2, 1, 4, 3]).
Anyway, to be able to sort the frozensets you need to make them ordered elements, for instance by converting to tuple. You can do this transparently using the key parameter of sorted
l = [frozenset({'2'}), frozenset({'1'}), frozenset({'4'}), frozenset({'3'})]
sorted(l, key=tuple)
or natsorted for strings with multiple digits:
from natsort import natsorted
l = [frozenset({'2'}), frozenset({'1'}), frozenset({'14'}), frozenset({'3'})]
natsorted(l, key=tuple)
output:
[frozenset({'1'}), frozenset({'2'}), frozenset({'3'}), frozenset({'14'})]

Need to pull multiple values from python list comprehension?

I have a dictionary with tuple keys, like so:
(1111, 3454): 34.55555
(1123, 4665): 67.12
(1111, 9797): 5.09
I need to do a list comprehension that grabs the values for all entries with a matching first element.
Problem is, I ALSO need that second value of the tuple...
interimlist = [v for k,v in mydict.items() if k[0]==item[0]]
Is what I've got right now for pulling the values if the first element of the tuple is correct (item is an iterator variable). I'd like the output to be a list of tuples of (value, second tuple number), so with the example points, would be the following output if item[0] is 1111:
[(34.55555, 3454), (5.09, 9797)]
The dict is not stored with a good with a good structure here. All the keys/vals must be iterated in order to do one lookup, so it is O(n) retrieval.
You should do a once-off re-keying of the data, adding another level of nesting in the dict:
>>> d
{(1111, 3454): 34.55555, (1123, 4665): 67.12, (1111, 9797): 5.09}
>>> d_new = {}
>>> for (k1, k2), v in d.items():
... if k1 not in d_new:
... d_new[k1] = {}
... d_new[k1][k2] = v
And now, O(1) lookups are restored:
>>> d_new[1111]
{3454: 34.55555, 9797: 5.09}
>>> [item[::-1] for item in d_new[1111].items()]
[(34.55555, 3454), (5.09, 9797)]

Multi Dimensional List - Sum Integer Element X by Common String Element Y

I have a multi dimensional list:
multiDimList = [['a',1],['a',1],['a',1],['b',2],['c',3],['c',3]]
I'm trying to sum the instances of element [1] where element [0] is common.
To put it more clearly, my desired output is another multi dimensional list:
multiDimListSum = [['a',3],['b',2],['c',6]]
I see I can access, say the value '2' in multiDimList by
x = multiDimList [3][1]
so I can grab the individual elements, and could probably build some sort of function to do this job, but it'd would be disgusting.
Does anyone have a suggestion of how to do this pythonically?
Assuming your actual sequence has similar elements grouped together as in your example (all instances of 'a', 'b' etc. together), you can use itertools.groupby() and operator.itemgetter():
from itertools import groupby
from operator import itemgetter
[[k, sum(v[1] for v in g)] for k, g in groupby(multiDimList, itemgetter(0))]
# result: [['a', 3], ['b', 2], ['c', 6]]
Zero Piraeus's answer covers the case when field entries are grouped in order. If they're not, then the following is short and reasonably efficient.
from collections import Counter
reduce(lambda c,x: c.update({x[0]: x[1]}) or c, multiDimList, Counter())
This returns a collection, accessible by element name. If you prefer it as a list you can call the .items() method on it, but note that the order of the labels in the output may be different from the order in the input even in the cases where the input was consistently ordered.
You could use a dict to accumulate the total associated to each string
d = {}
multiDimList = [['a',1],['a',1],['a',1],['b',2],['c',3],['c',3]]
for string, value in multiDimList:
# Retrieves the current value in the dict if it exists or 0
current_value = d.get(string, 0)
d[string] += value
print d # {'a': 3, 'b': 2, 'c': 6}
You can then access the value for b by using d["b"].

How to fetch the key/value pair of a dictionary only containing one item?

Let's say I have dict. I don't know the key/value inside. How do I get this key and the value without doing a for loop (there is only one item in the dict).
You might wonder why I am using a dictionary in that case. I have dictionaries all over my API and I don't want the user to be lost. It's only a matter of consistency. Otherwise, I would have used a list and indexes.
Use the proper data type for the job. Your goal should be to have workable code, not that you use the same data type all over the place.
If your dictionary only contains one key and one value, you can get either with indexing:
key = list(d)[0]
value = list(d.values())[0]
or to get both:
key, value = list(d.items())[0]
The list calls are needed because in Python 3, .keys(), .values() and .items() return dict views, not lists.
Another option is to use sequence unpacking:
key, = d
value, = d.values()
or for both at the same time:
(key, value), = d.items()
Just get the first item in the dictionary using an iterator
>>> d = {"foo":"bar"}
>>> k, v = next(iter(d.items()))
>>> k
'foo'
>>> v
'bar'
You can do this:
>>> d={1:'one'}
>>> k=list(d)[0]
>>> v=d[k]
Works in Python 2 or 3
d.popitem() will give you a key,value tuple.

Comparing Two Arrays resulting into Third Array

I have two Arrays:
firstArray=[['AF','AFGHANISTAN'],['AL','ALBANIA'],['DZ','ALGERIA'],['AS','AMERICAN SAMOA']]
secondArray=[[1,'AFGHANISTAN'],[3,'AMERICAN SAMOA']]
So I just need an Array which is like
thirdArray=[[1,'AF'],[3,'AS']]
I tried any(e[1] == firstArray[i][1] for e in secondArray)
It returned me True and false if second element of both array matches. but i don't know how to build the third array.
First, convert firstArray into a dict with the country as the key and abbreviation as the value, then just look up the abbreviation for each country in secondArray using a list comprehension:
abbrevDict = {country: abbrev for abbrev, country in firstArray}
thirdArray = [[key, abbrevDict[country]] for key, country in secondArray]
If you are on a Python version without dict comprehensions (2.6 and below) you can use the following to create abbrevDict:
abbrevDict = dict((country, abbrev) for abbrev, country in firstArray)
Or the more concise but less readable:
abbrevDict = dict(map(reversed, firstArray))
It is better to store them into dictionaries:
firstDictionary = {key:value for value, key in firstArray}
# in older versions of Python:
# firstDictionary = dict((key, value) for value, key in firstArray)
then you could get the 3rd array simply by dictionary look-up:
thirdArray = [[value, firstDictionary[key]] for value, key in secondArray]
You could use an interim dict as a lookup:
firstArray=[['AF','AFGHANISTAN'],['AL','ALBANIA'],['DZ','ALGERIA'],['AS','AMERICAN SAMOA']]
secondArray=[[1,'AFGHANISTAN'],[3,'AMERICAN SAMOA']]
lookup = {snd:fst for fst, snd in firstArray}
thirdArray = [[n, lookup[name]] for n, name in secondArray]
If a dictionary would do, there is a special purpose Counter dictionary for exactly this use case.
>>> from collections import Counter
>>> Counter(firstArray + secondArray)
Counter({['AF','AFGHANISTAN']: 1 ... })
Note that the arguments are reversed from what you requested, but that's easily remedied.
The standard way to match data to a key is a dictionary. You can convert firstArray to a dictionary using dict comprehension.
firstDict = {x: y for (y, x) in firstArray}
You can then iterate over your second array using list comprehension.
[[i[0], firstDict[i[1]]] for i in secondArray]
use a list comprehension:
In [119]: fa=[['AF','AFGHANISTAN'],['AL','ALBANIA'],['DZ','ALGERIA'],['AS','AMERICAN SAMOA']]
In [120]: sa=[[1,'AFGHANISTAN'],[3,'AMERICAN SAMOA']]
In [121]: [[y[0],x[0]] for x in fa for y in sa if y[1]==x[1]]
Out[121]: [[1, 'AF'], [3, 'AS']]

Categories

Resources