iterating over non-interpolated Array of symbols python equivalent - python

I am currently writing script in python from a ruby module. I am having trouble with this aspect of the translation of ruby to python.
Ruby:
plan_metrics[test_name]={ passed_count: 0, blocked_count: 0, untested_count: 0, failed_count: 0, reviewed_count: 0, test_harness_issue_count: 0, bug_failure_count: 0, defect_list: [] }
entry['runs'].each do |run|
metric_hash = plan_metrics[test_name]
%i[passed_count blocked_count untested_count failed_count].each do |key|
metric_hash[key] = metric_hash[key] + run[key.to_s]
end
In this code, entry['runs'] holds the actual values of passed_count, blocked_count, untested_count, and failed_count, but in multiple dictionaries. This is supposed to iterate over them and add up all the values and put them into ONE symbol (i.e passed_count) that is held in metric_hash
Now when i try to translate into python, i am not using symbols but instead doing it like this
My Python translation:
plan_metrics[test_name]={ "passed_count": 0, "blocked_count": 0, "untested_count": 0, "failed_count": 0, "reviewed_count": 0, "test_harness_issue_count": 0, "bug_failure_count": 0, "defect_list": [] }
for run in entry["runs"]:
metric_hash = plan_metrics[test_name]
for key in [metric_hash["passed_count"], metric_hash["blocked_count"], metric_hash["untested_count"], metric_hash["failed_count"]:
metric_hash[key] = metric_hash[key] + run[str(key)]
But for this i am getting KeyError: 0 on line metric_hash[key] = metric_hash[key] + run[str(key)]
would
for key in [metric_hash["passed_count"], metric_hash["blocked_count"], metric_hash["untested_count"], metric_hash["failed_count"]:
be the proper equivalent of
%i[passed_count blocked_count untested_count failed_count].each do |key|
and if so what is causing the KeyError: 0?
if not how can i accomplish what the ruby example did, with interating over array of symbols, in python
If you need more information on the data, letme know what to print() thanks

In python you do
for key in [metric_hash["passed_count"], metric_hash["blocked_count"], metric_hash["untested_count"], metric_hash["failed_count"]:
That means that key takes values from a list [0, 0, 0, 0]. Do you see why?

Related

Insertion Problem with Multiple-Value Python Dictionary

I am new to Python, so please be easy on me. I am using a dictionary to store multiple values for one key, however, I am having problems when I try to update values. Here is how I set up my dictionary; first, I write the first values using setdefault():
dictionary.setdefault(id.ID, []).append(id.enterTime)
dictionary.setdefault(id.ID, []).append(id.duration)
dictionary.setdefault(id.ID, []).append(id.enter)
dictionary.setdefault(id.ID, []).append(id.exit)
dictionary.setdefault(id.ID, []).append(id.standing)
dictionary.setdefault(id.ID, []).append(id.sitting)
For the sake of explanation, lets say that it produces the following output when printed:
{0: [5, 120, 0, 0, 0, 0]}
When the id.enter instance variable is changed, I update the dictionary using the following code by just removing the original value and appending the new value to the dictionary:
dictionary[id.ID].remove(id.enter)
dictionary[id.ID].insert(2, id.enter)
The dictionary prints as follows:
{0: [5, 120, 1, 0, 0, 0]}
Later in the program, the instance variable id.exit becomes 1. I attempted to change the exit value, after it had been updated from 0 to 1, in the dictionary as follows:
dictionary[id.ID].remove(id.exit)
dictionary[id.ID].insert(3, id.exit)
Very bad way to do it, I know, but I thought this would be the easiest way to update the values. When I do this, a problem occurs as it changes the id.enter back to its original value but updates the id.exit:
{0: [5, 120, 0, 1, 0, 0]}
Does anyone know why this would happen? Thanks.
The answer from use #mkrieger1 explains the problem/error with your code and gives a quick solution.
Another approach to store the data could be to use nested dicts to make it clearer and less error-prone:
my_dict = {
id.ID: {
'enterTime': id.enterTime,
'duration': id.duration,
'enter': id.enter,
'exit': id.exit,
'standing': id.standing,
'sitting': id.sitting,
}
}
Or even better with a defaultdict:
import collections
my_dict = collections.defaultdict(lambda: {
'enterTime': 0,
'duration': 0,
'enter': 0,
'exit': 0,
'standing': 0,
'sitting': 0,
})
print(my_dict)
# defaultdict(<function <lambda> at 0x7f327d094ae8>, {})
# add a new ID, it creates the nested dict automatically
my_dict[object_1.ID]['exit'] = object_1.exit
print(my_dict)
# defaultdict(<function <lambda> at 0x7f327d094ae8>, {1: {'enterTime': 0, 'duration': 0, 'enter': 0, 'exit': 5, 'standing': 0, 'sitting': 0}})
As explained in the tutorial:
list.remove(x)
Remove the first item from the list whose value is equal to x. It raises a ValueError if there is no such item.
So if you have the list
[5, 120, 1, 0, 0, 0]
and use remove(id.exit), when id.exit is equal to 1, then the list becomes:
[5, 120, 0, 0, 0]
As a simple solution, instead of
dictionary[id.ID].remove(id.exit)
dictionary[id.ID].insert(3, id.exit)
just use
dictionary[id.ID][3] = id.exit

Create List with variable length in Python

testList= []
testList[12]= 31
testList[23]= 1337
Error: IndexError: list assignment index out of range
Basically I have unique Integers and I want to use the lists for a hash function h(x)= x (because they are unique)
I could initialize the length like this:
testList= [0 for i in range(50)]
But then I have to fix the size and my unique numbers which I have increase with time. Is it ok to set the size to for example 1-2Mio or is there a way to do this dynamically?
ArrayList<> in Java is dynamically for append and delete but so are Lists in Python also.
Thanks!
Perhaps you need a dict:
testList = {}
testList[12]= 31
testList[23]= 1337
print(testList)
print(testList[23])
Output:
{12: 31, 23: 1337}
1337
If you don't want to use a dictionary (which I do think you should do), you could create your own auto-extensible list:
class defaultlist(list):
def __init__(self,defData):
self.defData = defData
def _getDefault(self):
if isinstance(self.defData,type):
return self.defData()
return self.defData
def __getitem__(self,index):
if index >= len(self):
return self._getDefault()
return super.__getitem__(index)
def __setitem__(self,index,value):
while index>=len(self):
self.append(self._getDefault())
list.__setitem__(self,index,value)
testList = defaultlist(0) # need to provide a default value for auto-created items
testList[12]= 31
testList[23]= 1337
print(testList)
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1337]

Divide integer by a list to create a new list

I've created a list of number in a specified range. I now want to divide an value by each element in the list, and then add that new value to a new list.
Heres what I've got:
Y = []
value = 55 #can be any value of my choosing
newx = list(range(50,500,10))
newy = value/(newx)**2
Y.append(newy)
I keep getting TypeError with unsupported operand types for ** or pow(): list and int and I don't know why. NOTE: The ** is a syntax for power i.e 1/(x^2)
One "clean" option to do it is to use numpy array:
import numpy as np
value = 55 #can be any value of my choosing
Y = np.arange(50,500,10)
Y = value/(Y)**2
You got an error since in python you cannot take a square of a list (and you also cannot devide a number by a list). numpy array allows you to take a square and to do this division and many other mathematical operations.
Your description says what you want to do: divide a value by each element in a list. But that's not what you're actually doing, which is trying to divide the value by the list itself. You should do what you say you want to:
Y = [value/v for v in newx]
(I don't understand what the ** is for, you don't mention that anywhere.)
You can just use a list comprehension :
newy = [value/x**2 for x in newx]
The error you get is because the square of a list isn't defined.
The square of a numpy.array is defined though, and would be a new array with the square of each element from the original array.
Depending on the value and range you're working with, you might want to convert the int to float first. You could get 0s otherwise :
>>> value = 55
>>> newx = range(50, 500, 10)
>>> [value/x**2 for x in newx]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
But :
>>> [value/float(x)**2 for x in newx]
[0.022, 0.015277777777777777, 0.011224489795918367, 0.00859375, 0.006790123456790123, 0.0055, 0.004545454545454545, 0.0038194444444444443, 0.003254437869822485, 0.0028061224489795917, 0.0024444444444444444, 0.0021484375, 0.0019031141868512112, 0.0016975308641975309, 0.0015235457063711912, 0.001375, 0.0012471655328798186, 0.0011363636363636363, 0.0010396975425330812, 0.0009548611111111111, 0.00088, 0.0008136094674556213, 0.0007544581618655693, 0.0007015306122448979, 0.0006539833531510107, 0.0006111111111111111, 0.0005723204994797086, 0.000537109375, 0.000505050505050505, 0.0004757785467128028, 0.0004489795918367347, 0.0004243827160493827, 0.00040175310445580715, 0.0003808864265927978, 0.0003616042077580539, 0.00034375, 0.0003271861986912552, 0.00031179138321995464, 0.00029745808545159546, 0.0002840909090909091, 0.00027160493827160494, 0.0002599243856332703, 0.00024898143956541424, 0.00023871527777777777, 0.00022907122032486465]

Fill missing values in lists

I have a list which consists of 0's and 1's. The list should ideally look like this 0,1,0,1,0,1,0,1,0,1,0,1,0,1.....
But due to some error in logging, my list looks like this: 0,1,0,1,1,1,0,1,0,0,0,1,0,1.... As one can clearly there are some missed 0's and 1's in middle. How can I fix this list to add those 0's and 1's in between the missing elements so as to get to the desired list values.
Here is the code used by me, this does the task for me but it is not the most pythonic way of writing scripts. So how can I improve on this script?
l1 = [0,1,0,1,1,1,0,1,0,0,0,1,0,1]
indices = []
for i in range(1,len(l1)):
if l1[i]!=l1[i-1]:
continue
else:
if l1[i]==0:
val=1
else:
val=0
l1.insert(i, val)
EDIT
As asked in the comments, Let me explain why is this important rather than generating 1's and 0's. I have TTL pulse coming i.e. a series of HIGH(1) and LOW(0) coming in and simultaneously time for each of these TTL pulse is logged on 2 machines with different clocks.
Now while machine I is extremely stable and logging each sequence of HIGH(1) and low(1) accurately, the other machine ends up missing a couple of them and as a result I don't have time information for those.
All I wanted was to merge the missing TTL pulse on one machine wrt to the other machine. This will now allow me to align time on both of them or log None for not received pulse.
Reason for doing this rather than correcting the logging thing (as asked in comments) is that this is an old collected data. We have now fixed the logging issue.
You can try something like this:
from itertools import chain
l1 = [0,1,0,1,1,1,0,1,0,0,0,1,0,1]
c = max(l1.count(0), l1.count(1))
print list(chain(*zip([0]*c,[1]*c)))
Output:
[0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
why would you have a list of 0,1,0,1,0,1? there is no good reason i can think of. oh well thats beyond the scope of this question i guess...
list(itertools.islice(itertools.cycle([0,1]),expected_length))
Just multiply a new list.
>>> l1 = [0,1,0,1,1,1,0,1,0,0,0,1,0,1]
>>> l1
[0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1]
>>> [0,1] * (len(l1)//2)
[0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
If the list has an odd number of elements, add the necessary 0:
>>> l2 = [0,1,0,1,1,1,0,1,0,0,0,1,0,1,0]
>>> l2_ = [0,1] * (len(l1)//2)
>>> if len(l2)%2: l2_.append(0)
...
>>> l2
[0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0]
>>> l2_
[0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]

openpyxl: find highest row for each column

I'm new to python programming. I've written a script to get data from an api (using python 2.7.8), and now I'd like to add it to an excel spreadsheet where I keep all my data.
In my spreadsheet, each row is one day, but some of the data doesn't become available until up to 30 days later, so some of my columns are not full all the way to the current date. Basically, not all my column lengths are the same.
I'd like to read each column, find the highest row for that column, and then add my data points to the end of that column. If all columns were the same length, this would be simple, but I don't understand how to find the length of each column separately.
I've read through the docs for openpyxl, but I'm new to python and I don't really understand everything. I think the solution will involve something like 'for each column, get the highest row', and then I would append each data point to that column. but I don't understand how to do the 'for each column' part. Finding the length of each column would also work.
thanks in advance
Edit: I came up with a work around: I know the relative length of the columns so I subtracted that from the number for the last row:
last_row = ws.get_highest_row() + 1
col_num = 1
dataRow_length = len(dataRow)
row_offset = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 7, 14, 28, 1, 2, 3, 7, 14, 28]
for i in range(0, dataRow_length - 1):
ws.cell(row=(last_row - row_offset[col_num - 1]), column=col_num).value = dataRow[i]
col_num = col_num + 1
If you iterate over the rows of a worksheet you can always find the length of a row. That should be sufficient for your purposes. If not, please supply some of your code so it's clearer as to what exactly you want to do.

Categories

Resources