Extending a dictionary by adding to tupled value - python

(I'm just using things to represent the format my dictionary is like, this is not how it actually looks)
The current dictionary I have is in the format of :
dict={"a":(1,2,3),"b":(2,3,4),"c":(3,4,5)}
dict2={1:(1,1,2),2:(2,2,3),3:(3,3,4)}
I am trying to add on to it. I have a function that calculated an average and now I want to create a second function that would pull that average from the first function and add it to the tuple in the values of my dictionary. So if the average was 4 for "a", then I would want to add it on for it to look like this {"a":(1,2,3,4)} etc.
def func1(dict, dict2, number):
if number in dict:
for num in dict.values():
#return sum after iteration of sum through num[0] to num[2]
def func 2 (dict1, dict2)
if number in dict:
new_val_to_add= func1(dict, dict2, number)
From here I'm not sure where I would go with adding the returned value to the tuple and be able to print back dict with the added value. I was thinking of maybe converting the tuple in the first dictionary into a list and then append to that as I iterate through each key in the dictionary, and finally convert it back into a tuple. Would this be the right way of going about this?

If you want the values to be mutable, why don't you use lists instead of tuples?
You can combine two tuples using +, though:
>>> (1, 2, 3) + (4,)
(1, 2, 3, 4)
I'm having trouble following your example code, but with a dictionary following your description you can do it like this:
>>> d1 = {'a': (1, 2, 3)}
>>> d1['a'] += (4,)
>>> d1
{'a': (1, 2, 3, 4)}
Or, using a list instead:
>>> d1 = {'a': [1, 2, 3]}
>>> d1['a'].append(4)
>>> d1
{'a': [1, 2, 3, 4]}

Related

Using zip on the results of itertools.groupby unexpectedly gives empty lists

I've encountered some unexpected empty lists when using zip to transpose the results of itertools.groupby. In reality my data is a bunch of objects, but for simplicity let's say my starting data is this list:
> a = [1, 1, 1, 2, 1, 3, 3, 2, 1]
I want to group the duplicates, so I use itertools.groupby (sorting first, because otherwise groupby only groups consecutive duplicates):
from itertools import groupby
duplicates = groupby(sorted(a))
This gives an itertools.groupby object which when converted to a list gives
[(1, <itertools._grouper object at 0x7fb3fdd86850>), (2, <itertools._grouper object at 0x7fb3fdd91700>), (3, <itertools._grouper object at 0x7fb3fdce7430>)]
So far, so good. But now I want to transpose the results so I have a list of the unique values, [1, 2, 3], and a list of the items in each duplicate group, [<itertools._grouper object ...>, ...]. For this I used the solution in this answer on using zip to "unzip":
>>> keys, values = zip(*duplicates)
>>> print(keys)
(1, 2, 3)
>>> print(values)
(<itertools._grouper object at 0x7fb3fdd37940>, <itertools._grouper object at 0x7fb3fddfb040>, <itertools._grouper object at 0x7fb3fddfb250>)
But when I try to read the itertools._grouper objects, I get a bunch of empty lists:
>>> for value in values:
... print(list(value))
...
[]
[]
[]
What's going on? Shouldn't each value contain the duplicates in the original list, i.e. (1, 1, 1, 1, 1), (2, 2) and (3, 3)?
Ah. The beauty of multiple iterator all using the same underlying object.
The documentation of groupby addresses this very issue:
The returned group is itself an iterator that shares the underlying iterable with groupby(). Because the source is shared, when the groupby() object is advanced, the previous group is no longer visible. So, if that data is needed later, it should be stored as a list:
groups = []
uniquekeys = []
data = sorted(data, key=keyfunc)
for k, g in groupby(data, keyfunc):
groups.append(list(g)) # Store group iterator as a list
uniquekeys.append(k)
So what ends up happening is that all your itertools._grouper objects are consumed before you ever unpack them. You see a similar effect if you try reusing any other iterator more than once. If you want to understand better, look at the next paragraph in the docs, which shows how the internals of groupby actually work.
Part of what helped me understand this is to work examples with a more obviously non-reusable iterator, like a file object. It helps to dissociate from the idea of an underlying buffer you can just keep track of.
A simple fix is to consume the objects yourself, as the documentation recommends:
# This is an iterator over a list:
duplicates = groupby(sorted(a))
# If you convert duplicates to a list, you consume it
# Don't store _grouper objects: consume them yourself:
keys, values = zip(*((key, list(value)) for key, value in duplicates)
As the other answer suggests, you don't need an O(N log N) solution that involves sorting, since you can do this in O(N) time in a single pass. Rather than use a Counter, though, I'd recommend a defaultdict to help store the lists:
from collections import defaultdict
result = defaultdict(list)
for item in a:
result[item].append(item)
For more complex objects, you'd index with key(item) instead of item.
To have grouping by each unique key for duplicate processing:
import itertools
a = [1, 1, 1, 2, 1, 3, 3, 2, 1]
g1 = itertools.groupby(sorted(a))
for k,v in g1:
print(f"Key {k} has", end=" ")
for e in v:
print(e, end=" ")
print()
# Key 1 has 1 1 1 1 1
# Key 2 has 2 2
# Key 3 has 3 3
If it's just for counting how many, with minimal sorting:
import itertools
import collections
a = [1, 1, 1, 2, 1, 3, 3, 2, 1]
g1 = itertools.groupby(a)
c1 = collections.Counter()
for k,v in g1:
l = len(tuple(v))
c1[k] += l
for k,v in c1.items():
print(f"Element {k} repeated {v} times")
# Element 1 repeated 5 times
# Element 2 repeated 2 times
# Element 3 repeated 2 times

Declaring multiple variables using the same function in Python

Long-hand this is how it would look like:
class TestClass(object):
def f(num):
"""In general, a complicated function."""
return num
self.a = f(1)
self.b = f(2)
self.c = f(3)
self.d = f(4)
self.e = f(5)
I'm thinking dictionary methods could help, but how?
As you said you better to use a dictionary.And as a more pythonic way you can use a dictionary comprehension.You can use enumerate to create a sequence of keys for your dictionary based on your items index. :
>>> my_dict = {'a{}'.format(i):f(j) for i,j in enumerate([3,4,5,1,2])}
{'a1': 4, 'a0': 3, 'a3': 1, 'a2': 5, 'a4': 2}
And for accessing to each value you can use a simple indexing :
>>> my_dict['a3']
1
Also if you want to use custom names for your keys you can use zip function to zip the variable names with values the use if within a dict comprehension:
>>> var_names=['a','b','c','d','e']
>>> values=[1,2,3,4,5]
>>>
>>> my_dict = {i:f(j) for i,j in zip(var_names,values)}
>>> my_dict
{'a': 1, 'c': 3, 'b': 2, 'e': 5, 'd': 4}
You're going in the wrong direction - if you want to assign several references based on the same function, you should be storing them in a data structure like a list instead of in discrete, manually-entered variables. You can unpack them like that later if you want, but you should start with a data structure. It then becomes easier to map() each value in an iterable to this function, and then turn it into a list.
def f(num):
"""In general, a complicated function."""
return num
my_numbers = list(map(f, range(1, 6)))
Your numbers were a tidy range this time so I just used a range() object, but you can use any iterable you like, such as [1, 2, 3] or (4, 2, 3).

How to dict(zip) for every item on list?

Here is the code:
kws = [1, 2, 3]
ab = dict(zip(['keyword:'], kws))
print ab
But it only returns: {'keyword:': 1}
I want to make it return: {'keyword:': 1, 'keyword:': 2, 'keyword:': 3}
Vignesh Kalai's comment is correct, but if you just want tuples, try:
ab = zip((['keyword'] * len(kws)), kws)
python dictionaries don't support multiple keys which is what you are trying to do, but you can have a key mapped to a list. So you could have
{keyword: [1, 2, 3]}
just by doing
kws = [1,2,3]
ab = {}
ab['Keyword'] = kws
print ab
{'Keyword': [1, 2, 3]}
Dictionary can't have same key.
Sorry, it's principle of dictionary. You question is requiring a invalid result.
I know everyone doesn't like your question.
I recommend you make list-tuple object to keep your data structure. Let's try to change the method.
print [('keyword', kw) for kw in kws]
# [('keyword', 1), ('keyword', 2), ('keyword', 3)]
So, it can simulate key-value pair. I think it can satisfy your needed.

Converting string list into integer list beginning from 1

I want to know a method to convert a list of strings such as:
myList = ["Bob1", "Bob2", "Bob3", "Bob4"]
Somehow into integers so that they are 0, 1, 2, 3
And then so that they are 1, 2, 3, 4 and then once I've done my calculations, I need to return the answers to the correct string in myList.
The reason for wanting to do this is because I want to use these in nth term and to do that I need to do some arithmetic so I need to be able to use number/int values to be able to calculate them and then I can return them as string values once the arithmetic is complete, based on the final number/int result.
EDIT: Solved this.
Maybe:
>>> myList = ["Bob1", "Bob2", "Bob3", "Bob4"]
>>> range(1, len(myList) + 1)
[1, 2, 3, 4]
From what you are describing, you may want to use enumerate and operate on the integer in the tuples:
myList = ["Bob1", "Bob2", "Bob3", "Bob4"]
li=[(i,s) for i,s in enumerate(myList,1)]
print li
# [(1, 'Bob1'), (2, 'Bob2'), (3, 'Bob3'), (4, 'Bob4')]
Then you can operate on the int part of the tuple:
print [t[1] for t in li if not t[0]%2]
# ['Bob2', 'Bob4']
print sum(t[0] for t in li if not t[0]%2)
# 6
Then just peel the number off when you are done:
print [s for i,s in li]
# ['Bob1', 'Bob2', 'Bob3', 'Bob4']

Obtaining length of list as a value in dictionary in Python 2.7

I have two lists and dictionary as follows:
>>> var1=[1,2,3,4]
>>> var2=[5,6,7]
>>> dict={1:var1,2:var2}
I want to find the size of the mutable element from my dictionary i.e. the length of the value for a key.
After looking up the help('dict'), I could only find the function to return number of keys i.e. dict.__len__().
I tried the Java method(hoping that it could work) i.e. len(dict.items()[0]) but it evaluated to 2.
I intend to find this:
Length of value for first key: 4
Length of value for second key: 3
when the lists are a part of the dictionary and not as individual lists in case their length is len(list).
Any suggestions will be of great help.
dict.items() is a list containing all key/value-tuples of the dictionary, e.g.:
[(1, [1,2,3,4]), (2, [5,6,7])]
So if you write len(dict.items()[0]), then you ask for the length of the first tuple of that items-list. Since the tuples of dictionaries are always 2-tuples (pairs), you get the length 2. If you want the length of a value for a given key, then write:
len(dict[key])
Aso: Try not to use the names of standard types (like str, dict, set etc.) as variable names. Python does not complain, but it hides the type names and may result in unexpected behaviour.
You can do this using a dict comprehension, for example:
>>> var1 = [1,2,3,4]
>>> var2 = [5,6,7]
>>> d = {1:var1, 2:var2}
>>> lengths = {key:len(value) for key,value in d.iteritems()}
>>> lengths
{1: 4, 2: 3}
Your "Java" method would also nearly have worked, by the way (but is rather unpythonic). You just used the wrong index:
>>> d.items()
[(1, [1, 2, 3, 4]), (2, [5, 6, 7])]
>>> d.items()[0]
(1, [1, 2, 3, 4])
>>> len(d.items()[0][1])
4
>>>for k,v in dict.iteritems():
k,len(v)
ans:-
(1, 4)
(2, 3)
or
>>>var1=[1,2,3,4]
>>>var2=[5,6,7]
>>>dict={1:var1,2:var2}
ans:-
>>>[len(v) for k,v in dict.iteritems()]
[4, 3]

Categories