Save Results from cursor.callproc in dict - python-3.x

I'm trying to get some data from a MySQL database with a stored procedure and store it in a dict (as mentioned by blair here):
def createProduct(self):
self.cursor.callproc('newProduct')
result = []
for recordset in self.cursor.stored_results():
for row in recordset:
result.append(dict(zip(recordset.column_names,row)))
print(result)
The cursor is created with the option dictionary=True. The output for print(result) is:
[{'manufacturers_id': 0, 'alarm_threshold': 10, 'users_id_tech': 0, 'name': 'item1',
'entities_id': 0, 'notepad': None, 'locations_id': 0, 'groups_id_tech': 0,
'consumableitemtypes_id': 0, 'id': 1, 'comment': '', 'is_deleted': 0, 'ref': ''}]
I tried to access the value of the key name (which is item1) with this code:
print(result['name'])
TypeError: list indices must be integers, not str
and:
print(result(name))
NameError: name 'name' is not defined
I thought the code from blair would create a dict whose values are accessible by keys (for example 'name')? Is this wrong or what am I doing wrong?

Looking at the list of dictionary you posted, I think there is a problem with the way you are printing.
I think this
print(result['name'])
should become this
print(result[0]['name'])
since you are trying to acess a dictionary inside a list.
Hope it works.

Related

Comparing values from nested dictionaries in Python 3

I have some code that uses a nested dictionary to hold results from a linear regression. The program runs a regression on multiple sets of data ('targets'), and stores the regression variables for each target as a dictionary, and these dictionaries are contained within another dictionary using the target name as the key with the value being the dictionary holding the variables. It's initialized like this (note that self.targets is just a list of the different targets):
self.results = {}
for keys in self.targets:
self.results[keys] = {
'lod': '', 'p': '', 'm': '', 'b': '', 'xr': ''}
In another method that gets called within a for-loop, the values in the dictionary for that target are filled:
for tar in targets:
...some calculations to produce the values...
self.results[tar].update(
'lod': lod, 'p': p, 'm': m, 'b': b, 'xr': xr)
Later on, I want to plot the different regressions on one plot. To do that, I want to find the maximum value of xr from the sub-dictionaries (xr is the right-bound needed to plot each regression).
I tried accessing all the xr values like self.results[:]['xr']. That didn't work, so I pulled the xr values in a for-loop:
xrs = []
for tar in self.targets:
xrs.append(self.results[tar]['xr'])
and this gets the job done, as I can just do max(xrs) to find the largest value. I was wondering, though, if there was a more direct way to pull the maximum value of the 'xr' keys, without having to create a separate list as a middleman.
a generator comprehension might help:
data = {
"a" : {'lod': '', 'p': '', 'm': '', 'b': '', 'xr': 0},
"b" : {'lod': '', 'p': '', 'm': '', 'b': '', 'xr': 1}
}
max_xr = max(value["xr"] for value in data.values())
print(max_xr)
That should give you 1 I think.
The only way I can come up with is this. You essentially do what max() does without filling the list (assuming xr is > 0, otherwise use a very negative number for themax like -1e-6):
themax = 0 # initialise maximum
for tar in self.targets:
val = self.results[tar]['xr']
if val > themax:
themax = val
print(themax)
It will only save a minor amount of computation time at most, but I hope it helps.

Python: assigning and updating items in a list of dictionaries

my_list = []
my_item = {'number': 2}
for value in range(2):
my_list.append(my_item)
print(my_list)
my_list[1]['number'] = 20
print(my_list)
The code above produces the following output:
[{'number': 2}, {'number': 2}]
[{'number': 20}, {'number': 20}]
Question: why are both items in the list changed? This behavior does not occur if I put the assignment statement in line 2 inside the for loop in line 3. But why does it happen in this format?
my_item is a dict object that is located somewhere in memory. When you call my_list.append(my_item), you're putting another reference to that same dict object into the list. No matter how many times you append(my_item), you're referring to the exact same dict object. my_list[1] is just another name for that exact same dict object from before, so mutating my_list[1] will change the dict you see when you reference it using any other name, including my_list[0].
Putting my_item = {'number': 2} inside the for loop solves this problem because it creates a new object for my_item every time, which then gets appended to my_list.

How do i create a similarity matrix based on the below code?

I'm trying to use the gower function from this link https://sourceforge.net/projects/gower-distance-4python/files/. I'm trying to apply it to my dataframe of categorical variables. However I can see that when i use the gower_distances function i have some non-zero values in my diagonals ( i need them to all be 0).
I've been trying to de-bug the code. I think i know where this is happening and it's occuring in the _gower_distance_row function. There is this line of code which i don;t understand sij_cat = np.where(xi_cat == xj_cat,np.zeros_like(xi_cat),np.ones_like(xi_cat)). But i will present it in a easier format to understand.
Say i have:
xi=np.array(['cat','dog','monkey'])
xj=np.array([['cat','dog','monkey'],['horse','dog','hairy']])
sij_cat = np.where(xi == xj,np.zeros_like(xi),np.ones_like(xi))
I get this as my result:
array([['', '', ''],
['1', '', '1']], dtype='<U6')
since i am comparing cat with cat i want to assign zero, and where it is different e.g. cat vs horse and monkey vs hairy it should be 1. I don't get why in the above result i am getting ''? i want zeroes here. How do i fix this?
np.logical_not(xi == xj).astype(int)
output will be:
array([[0, 0, 0],
[1, 0, 1]])
explanation:
np.logical_not changes True to False and False to True and astype(int) changes to 0 and 1

How to replace the items from given dictionary?

I am a newbie in python. I was playing with dictionaries and wanted to know the solution to the given problem
list_ = [['any', 'window', 'says', 'window'], ['dog', 'great'], ['after', 'end', 'explains', 'income', '.', '?']]
dictionary=[('dog', 'cat'), ('window', 'any')]
def replace_matched_items(word_list, dictionary):
int_word = []
int_wordf = []
for lst in word_list:
for ind, item in enumerate(lst):
for key,value in dictionary:
if item in key:
lst[ind] = key
else:
lst[ind] = "NA"
int_word.append(lst)
int_wordf.append(int_word)
return int_wordf
list_ = replace_matched_items(list_, dictionary)
print(list_ )
Output generated is:
[[['NA', 'window', 'NA', 'window'], ['NA', 'NA'], ['NA', 'NA', 'NA', 'NA', 'NA', 'NA']]]
The expected output is:
[[['NA', 'window', 'NA', 'window'], ['dog', 'NA'], ['NA', 'NA', 'NA', 'NA', 'NA', 'NA']]]
I am using python 3
Thanks in advance
Some quick introduction to data structures in python just to clarify your question.
A list is similar to your arrays, where they can be accessed via their index and are mutable meaning items within the list can be changed. Lists are generally identified by brackets [].
For example:
my_array = [4, 8, 16, 32]
print(my_array[0]) # returns 4
print(my_array[3]) # returns 32
my_array[2] = 0
print(my_array) # returns [4, 8, 0, 32]
A tuple is similar to a list, however, the main difference is that they are immutable meaning items within the tuple cannot be changed. Items can still be accessed via their index. They are generally identified by parenthesis ().
For example:
my_tuple = ('this', 'is', 'a', 'tuple', 'of', 'strings')
print(my_tuple[0]) # returns 'this'
my_tuple[1] = 'word' # throws a 'TypeError' as items within tuples cannot be changed.
A dictionary uses a key and value pair to access, store, and change data in a dictionary. Similar to lists, they are mutable, however, each value has their own unique key. To access a value in the dictionary, you have to pass the key within the dictionary. Dictionaries are generally identified by curly braces {}.
For Example:
my_dictionary = {'John':13, 'Bob':31, 'Kelly':24, 'Ryan':17}
print(my_dictionary['Kelly']) # Returns 24
my_dictionary['Kelly'] = 56 # Assigns 56 to Kelly
print(my_dictionary['Kelly']) # Returns 56
The key:value takes this form within the dictionary, and each subsequent key-value pairs are separated by commas.
I would highly suggested reading the official documentation on the Data Structures available for python: Link Here
To answer the question
From your code given, you've used a tuple with your key-value pair encapsulated the tuple in a list as your dictionary data structure.
Your expected output is a result of you iterating through the entire dictionary, and did not handle what will occur once you've found the key for your dictionary. This can be fixed by adding a break statement within your if-statement once a key has been found.
The break statement, will exit your for loop once a key has been found and, will continue onto the next list item.
Your function will end up looking like:
def replace_matched_items(word_list, dictionary):
int_word = []
int_wordf = []
for lst in word_list:
for ind, item in enumerate(lst):
for key,value in dictionary:
if item in key:
lst[ind] = key
break
else:
lst[ind] = "NA"
int_word.append(lst)
int_wordf.append(int_word)
return int_wordf
Suggested to use a Dictionary
Using a Dictionary data structure for your key and value pairs will let you have access to methods that'll let you check whether a key exists inside your dictionary.
If you have a list of keys, and you'd like to check if a dictionary key exists within a list:
this_list = ['any', 'window', 'says', 'window', 'dog',
'great', 'after', 'end', 'explains', 'income', '.', '?']
dictionary = {'dog':'cat', 'window':'any'}
matched_list = []
for keys in dictionary:
if keys in this_list:
matched_list.append(keys) # adds keys that are matched
else:
# do something if the key is in not the dictionary
print(matched_list)
# Returns ['dog', 'window']

Python3.4 Dictionary value replacement issue

I have some code which takes a list of dictionaries and creates another list of dictionaries.
Each dictionary in the list has two key/value pairs "ID" and "opcode", where "opcode" is a 32 bit number.
My code needs to create a second list of dictionaries where the opcodes are separated, i.e. a dictionary with opcode=5 would become two dictionaries with opcode=1 and opcode=4.
(opcode is a 32 bit number and my requirement is that only 1 bit is high, ie opcode=1,2,4,8,16 etc)
I've simplified the problem into the following; my code needs to turn this:
part=[{"ID":1,"opcode":4},{"ID":2,"opcode":5},{"ID":3,"opcode":6}]
into this:
part_=[{"ID":1,"opcode":4},{"ID":2,"opcode":1},{"ID":2,"opcode":4},{"ID":3,"opcode":2},{"ID":3,"opcode":4}]
Currently my code is the following
def bit_set(theNumber,bit):
return theNumber&(1<<bit)!=0
part=[{"ID":1,"opcode":4},{"ID":2,"opcode":5},{"ID":3,"opcode":6}]
part_=[]
for i in part:
for j in range(32):
if bit_set(i["opcode"],j):
part_.append(i)
part_[-1]["opcode"]=(1<<j)
for i in part_:
print(i)
The output of the code is:
{'opcode': 4, 'ID': 1}
{'opcode': 1, 'ID': 2}
{'opcode': 2, 'ID': 3}
Interestingly if I modify the code slightly so that the value modification line is not there, the extra dictionaries are created, but obviously the opcode is not correct.
def bit_set(theNumber,bit):
return theNumber&(1<<bit)!=0
part=[{"ID":1,"opcode":4},{"ID":2,"opcode":5},{"ID":3,"opcode":6}]
part_=[]
for i in part:
for j in range(32):
if bit_set(i["opcode"],j):
part_.append(i)
#part_[-1]["opcode"]=(1<<j)
for i in part_:
print(i)
The output is
{'ID': 1, 'opcode': 4}
{'ID': 2, 'opcode': 5}
{'ID': 2, 'opcode': 5}
{'ID': 3, 'opcode': 6}
{'ID': 3, 'opcode': 6}
I can get around the issue by going about the problem a different way, but in the interest in learning what is going on I'm out of my depth.
This is caused as when you append i to the new list you do not create a copy of the dictionary instead you add a reference to the original dictionary. This means that when you change the dictionary in the next line you also change value in part. This causes the loop not to match the any more parts of the opcode. You can see this if you print out the values of part at the end of your code.
The python documentation explains this as:
Assignment statements in Python do not copy objects, they create bindings between a target and an object. For collections that are mutable or contain mutable items, a copy is sometimes needed so one can change one copy without changing the other.
Reference
You can fix this by creating a copy of the dictionary when you append it. This will allow you change the value without affecting the original dictionary. Python allows you to copy objects using the copy module (Documentation).
Just import copy and then do part_.append(copy.copy(i)) instead of part_.append(i).
import copy
def bit_set(theNumber,bit):
return theNumber&(1<<bit)!=0
part = [{"ID": 1, "opcode": 4}, {"ID": 2, "opcode": 5}, {"ID": 3, "opcode": 6}]
part_=[]
for i in part:
for j in range(32):
if bit_set(i["opcode"],j):
part_.append(copy.copy(i))
part_[-1]["opcode"]=(1<<j)
for i in part_:
print(i)

Resources