Python using array elements as indices in multidimension array - python

I'm parsing results from a SOAP query (wsdl) and getting the results in an array of arrays like:
[(item){
item[] =
(item){
key[] =
"cdr_id",
value[] =
"201407000000000431",
},
(item){
key[] =
"cdr_date",
value[] =
"2014-07-07 07:47:12",
},
... (snipped for brevity - 81 items in total)
(item){
key[] =
"extradata",
value[] = <empty>
},
}]
I need to extract a single value that corresponds to a particular key.
I have encountered 2 issues:
How to map keys to values? (Otherwise I nest for loops over result.item[][])
How to return value as integer?
I am quite new to python, so sorry in advance if question seems too simple.
My current code looks a bit like:
success_calls = client.service.selectRowset(tables[table], sfilter, None, None, None)[1]
total_time = calls_num = 0
for call in success_calls:
for key in range(len(call.item)):
if call.item[key][0] is "elapsed_time":
item_value = call.item[key][1]
total_time += int(item_value)

You can create a Dictionary for all these values to access specific values using a specific key. Dictionaries are pythons implementation of hashed tables. Note that this would only make sense if you like to access the dictionary multiple times because you need to run through your array during the creation of the hash-table and calculate a hash-value for every entry. If you only want to extract a single value, the best solution is to run through the array as you already do in your code example. In worst case you have a complexity O(n).
You can easily parse a String to Integer in python using int("12345"). But be careful. This can raise a ValueError exception if your string is not parseable to integer. If your elapsed_time is a real number and not a natural one you can parse is using float("22.2123")

Related

How to make a dictionary using two list but i want both two as a value And Key will be name and sys-id?

I have two values number and sys_id. I have made seperate list for both of the values. How can save it in any other data structure like dictionary, or something else because i those list of number and sys_id are related. I am doing it in Python
Below Is the code what i have done
ticket_num.append(resp['result'][idx]['number'])
sys_id.append(resp['result'][idx]['sys_id']) ```
This is making two list one for ticket_num and sys_id. As Ticket number and sys_id are related for example ticket_num = ['INC00012','INC00013','INC00014' ] ,
sys_id = ['644323432sfasesdf213', '644323432dfgdfkdskrwwr', 'f283044423fdldsf09']
As this list are related like ticket_num[0] is directly link with sys_id[0]
So can i make a dictionary that contains ticket_num, sys_id directly without creating lists(for e.g. : {ticket_num : '...' , sys_id = '....' , ..... }
Use zip with dict
Ex:
ticket_num = ['INC00012','INC00013','INC00014' ]
sys_id = ['644323432sfasesdf213', '644323432dfgdfkdskrwwr', 'f283044423fdldsf09']
print(dict(zip(ticket_num, sys_id)))
Output:
{'INC00012': '644323432sfasesdf213',
'INC00013': '644323432dfgdfkdskrwwr',
'INC00014': 'f283044423fdldsf09'}
Welcome to Stackoverflow.
Do you actually need the lists of ticket numbers and IDs? If not that you could instead consider building the structure you need instead of the lists.
You don't say whether you want to be able to look up IDs from ticket numbers or vice versa. This solution allows you to do either:
idx_from_ticket = {}
ticket_from_idx = {}
# In the loop that produces the values, instead of the current appends ...
temp = resp['result'][idx]
idx = temp['sys_id]
number = temp['number']
idx_from_ticket[number] = idx
ticket_from_idx[idx] = number
The two dictionaries can then be used to correlate the IDs and ticket numbers. If you want to actually do something else then I hope this code gives you enough clues.
If you do already have the lists and want to retain them then the zip function is your friend.
idx_from_ticket = dict(zip(ticket_num, sys_id))
ticket_from_idx = dict(zip(sys_id, ticket_num))
zip, when called with two argument, yields a sequence of two-element tuples, which the
dict function assumes are key/value pairs.

Python seems to randomly invert list items during long loop

I have an array of dictionaries of the form:
[
{
generic_key: specific_key,
generic_value: specific_value
}
...
]
I am trying to interpret this into an array of dictionaries of this form:
[
{
specific_key: specific_value
}
...
]
I tried this:
new_array = []
for row in old_array:
values = list(row.values())
key = values[0]
val = values[1]
new_array.append({key: val})
This works in most cases, but in some, it swaps them around to form a dict like this:
{
specific_value: specific_key
}
I've looked at the source file, and the rows in which it does this are identical to the rows in which it does not do this.
It's perhaps worth mentioning that the list in question is about 3000 elements in length.
Am I doing something stupid? I guess that maybe list(row.values()) does not necessarily preserve the order, but I don't see why it wouldn't.
EDIT fixed code typo suggesting that it was appending sets
The order in which dict keys/values are enumerated is ostensibly arbitrary (there's certainly a logic to it, and as of I think python3.7+, it's consistent, but while I don't know off the top of my head what the ordering criteria are) - if you wanted order, you would have used a list instead of a dict to store them in the first place. If generic_key and generic_value are the same each time, then the ideal way to handle this problem is to simply extract by key:
key = row['generic_key']
value = row['generic_value']
If this isn't the case but there is a consistent way to differentiate between generic_key and generic_value, then you can grab both the keys and values, and do that:
items = tuple(row.items())
if items[0][0] is the generic_key: # insert whatever condition you need to here
key = items[0][1]
value = items[1][1]
else
key = items[1][1]
value = items[0][1]

Updating dictionary with randint performing unexpectedly

I'm trying to run a simple program in which I'm trying to run random.randint() in a loop to update a dictionary value but it seems to be working incorrectly. It always seems to be generating the same value.
The program so far is given below. I'm trying to create a uniformly distributed population, but I'm unsure why this isn't working.
import random
__author__ = 'navin'
namelist={
"person1":{"age":23,"region":1},
"person2":{"age":24,"region":2},
"person3":{"age":25,"region":0}
}
def testfunction():
default_val={"age":23,"region":1}
for i in xrange(100):
namelist[i]=default_val
for index in namelist:
x = random.randint(0, 2)
namelist[index]['region']=x
print namelist
if __name__ == "__main__" :
testfunction()
I'm expecting the 103 people to be roughly uniformly distributed across region 0-2, but I'm getting everyone in region 0.
Any idea why this is happening? Have I incorrectly used randint?
It is because all your 100 dictionary entries created in the for loop refer to not only the same value, but the same object. Thus there are only 4 distinct dictionaries at all as the values - the 3 created initially and the fourth one that you add 100 times with keys 0-99.
This can be demonstrated with the id() function that returns distinct integer for each distinct object:
from collections import Counter
...
ids = [ id(i) for i in namelist.values() ]
print Counter(ids)
results in:
Counter({139830514626640: 100, 139830514505160: 1,
139830514504880: 1, 139830514505440: 1})
To get distinct dictionaries, you need to copy the default value:
namelist[i] = default_val.copy()
Or create a new dictionary on each loop
namelist[i] = {"age": 23, "region": 1}
default_val={"age":23,"region":1}
for i in xrange(100):
namelist[i]=default_val
This doesn't mean "set every entry to a dictionary with these particular age and region values". This means "set every entry to this particular dictionary object".
for index in namelist:
x = random.randint(0, 2)
namelist[index]['region']=x
Since every object in namelist is really the same dictionary, all modifications in this loop happen to the same dictionary, and the last value of x wipes the others.
Evaluating a dict literal creates a new dict; assignment does not. If you want to make a new dictionary each time, put the dict literal in the loop:
for i in xrange(100):
namelist[i]={"age":23,"region":1}
Wanted to add this as a comment but the link is too long. As others have said you have just shared the reference to the dictionary, if you want to see the visualisation you can check it out on Python Tutor it should help you grok what's happening.

accessing values from a list in python

If I had the following code
buttonParameters = [
("button1", "button1.png"),
("button2", "button2.png"),
("button3", "button3.png"),
("button4", "button4.png"),
("button5", "button5.png"),
]
how would I go about accessing "button1" from buttonParameters.
Also, what type of list structure is this? I was reccomended using it, but I'm not sure I know what it's name is, and would like to search some to understand it more.
It seems like you are trying to retrieve a Value from a mapping, given a Key.
For this you are using a List when you should be using a Dictionary:
buttonParameters = {
"button1": "button1.png",
"button2": "button2.png",
"button3": "button3.png",
"button4": "button4.png",
"button5": "button5.png",
}
buttonParameters['button1'] #=> "button1.png"
A solution involving a List traversal to extract a value has linear worst-case performance whilst dictionary retrieval is amortised constant time.
You can convert your list of tuples into the above dictionary with:
buttonParameters = dict(buttonParameters)

Python large list manipulation

I have python list like below:
DEMO_LIST = [
[{'unweighted_criket_data': [-46.14554728131345, 2.997789122813151, -23.66171024766996]},
{'weighted_criket_index_input': [-6.275794430258629, 0.4076993207025885, -3.2179925936831144]},
{'manual_weighted_cricket_data': [-11.536386820328362, 0.7494472807032877, -5.91542756191749]},
{'average_weighted_cricket_data': [-8.906090625293496, 0.5785733007029381, -4.566710077800302]}],
[{'unweighted_football_data': [-7.586729834820534, 3.9521665714843675, 5.702038461085529]},
{'weighted_football_data': [-3.512655913521907, 1.8298531225972623, 2.6400438074826]},
{'manual_weighted_football_data': [-1.8966824587051334, 0.9880416428710919, 1.4255096152713822]},
{'average_weighted_football_data': [-2.70466918611352, 1.4089473827341772, 2.0327767113769912]}],
[{'unweighted_rugby_data': [199.99999999999915, 53.91020408163265, -199.9999999999995]},
{'weighted_rugby_data': [3.3999999999999857, 0.9164734693877551, -3.3999999999999915]},
{'manual_rugby_data': [49.99999999999979, 13.477551020408162, -49.99999999999987]},
{'average_weighted_rugby_data': [26.699999999999886, 7.197012244897959, -26.699999999999932]}],
[{'unweighted_swimming_data': [2.1979283454982053, 14.079951031527246, -2.7585499298828777]},
{'weighted_swimming_data': [0.8462024130168091, 5.42078114713799, -1.062041723004908]},
{'manual_weighted_swimming_data': [0.5494820863745513, 3.5199877578818115, -0.6896374824707194]},
{'average_weighted_swimming_data': [0.6978422496956802, 4.470384452509901, -0.8758396027378137]}]]
I want to manipulate list items and do some basic math operation,like getting each data type list (example taking all first element of unweighted data and do sum etc)
Currently I am doing it like this.
The current solution is a very basic one, I want to do it in such way that if the list length is grown, it can automatically calculate the results. Right now there are four list, it can be 5 or 8,the final result should be the summation of all the first element of unweighted values,example:
now I am doing result_u1/4,result_u2/4,result_u3/4
I want it like result_u0/4,result_u1/4.......result_n4/4 # n is the number of list inside demo list
Any idea how I can do that?
(sorry for the beginner question)
You can implement a specific list class for yourself, that adds your summary with new item's values in append function, or decrease them on remove:
class MyList(list):
def __init__(self):
self.summary = 0
list.__init__(self)
def append(self, item):
self.summary += item.sample_value
list.append(self, item)
def remove(self, item):
self.summary -= item.sample_value
list.remove(self, item)
And a simple usage:
my_list = MyList()
print my_list.summary # Outputs 0
my_list.append({'sample_value': 10})
print my_list.summary # Outputs 10
In Python, whenever you start counting how many there are of something inside an iterable (a string, a list, a set, a collection of any of these) in order to loop over it - its a sign that your code can be revised.
Things can can work for 3 of something, can work for 300, 3000 and 3 million of the same thing without changing your code.
In your case, your logic is - "For every X inside DEMO_LIST, do something"
This translated into Python is:
for i in DEMO_LIST:
# do something with i
This snippet will run through any size of DEMO_LIST and each time i is each of whatever is in side DEMO_LIST. In your case it is the list that contains your dictionaries.
Further expanding on that, you can say:
for i in DEMO_LIST:
for k in i:
# now you are in each list that is inside the outer DEMO_LIST
Expanding this to do a practical example; a sum of all unweighted_criket_data:
all_unweighted_cricket_data = []
for i in DEMO_LIST:
for k in i:
if 'unweighted_criket_data' in k:
for data in k['unweighted_cricket_data']:
all_unweighted_cricked_data.append(data)
sum_of_data = sum(all_unweighted_cricket_data)
There are various "shortcuts" to do the same, but you can appreciate those once you understand the "expanded" version of what the shortcut is trying to do.
Remember there is nothing wrong with writing it out the 'long way' especially when you are not sure of the best way to do something. Once you are comfortable with the logic, then you can use shortcuts like list comprehensions.
Start by replacing this:
for i in range(0,len(data_list)-1):
result_u1+=data_list[i][0].values()[0][0]
result_u2+=data_list[i][0].values()[0][1]
result_u3+=data_list[i][0].values()[0][2]
print "UNWEIGHTED",result_u1/4,result_u2/4,result_u3/4
With this:
sz = len(data_list[i][0].values()[0])
result_u = [0] * sz
for i in range(0,len(data_list)-1):
for j in range(0,sz):
result_u[j] += data_list[i][0].values()[0][j]
print "UNWEIGHTED", [x/len(data_list) for x in result_u]
Apply similar changes elsewhere. This assumes that your data really is "rectangular", that is to say every corresponding inner list has the same number of values.
A slightly more "Pythonic"[*] version of:
for j in range(0,sz):
result_u[j] += data_list[i][0].values()[0][j]
is:
for j, dataval in enumerate(data_list[i][0].values()[0]):
result_u[j] += dataval
There are some problems with your code, though:
values()[0] might give you any of the values in the dictionary, since dictionaries are unordered. Maybe it happens to give you the unweighted data, maybe not.
I'm confused why you're looping on the range 0 to len(data_list)-1: if you want to include all the sports you need 0 to len(data_list), because the second parameter to range, the upper limit, is excluded.
You could perhaps consider reformatting your data more like this:
DEMO_LIST = {
'cricket' : {
'unweighted' : [1,2,3],
'weighted' : [4,5,6],
'manual' : [7,8,9],
'average' : [10,11,12],
},
'rugby' : ...
}
Once you have the same keys in each sport's dictionary, you can replace values()[0] with ['unweighted'], so you'll always get the right dictionary entry. And once you have a whole lot of dictionaries all with the same keys, you can replace them with a class or a named tuple, to define/enforce that those are the values that must always be present:
import collections
Sport = collections.namedtuple('Sport', 'unweighted weighted manual average')
DEMO_LIST = {
'cricket' : Sport(
unweighted = [1,2,3],
weighted = [4,5,6],
manual = [7,8,9],
average = [10,11,12],
),
'rugby' : ...
}
Now you can replace ['unweighted'] with .unweighted.
[*] The word "Pythonic" officially means something like, "done in the style of a Python programmer, taking advantage of any useful Python features to produce the best idiomatic Python code". In practice it usually means "I prefer this, and I'm a Python programmer, therefore this is the correct way to write Python". It's an argument by authority if you're Guido van Rossum, or by appeal to nebulous authority if you're not. In almost all circumstances it can be replaced with "good IMO" without changing the sense of the sentence ;-)

Categories