Python List Comprehensions Help

101 posts now
What should I mark as the solution?
I should mark one and ask even similar questions in other threads?

So many solutions, highlighting comments:
5, 16, 14, 40, 49, 67 , 71
+/- 1 as I don’t really know how comments are counted.

I don’t understand comment 57 by Jordan, the dictionary is complex and I did not follow how it worked.
Even with the post linked to using the nested dictionaries, I’m still not sure.

The url should tell you the id of the highest VISIBLE comment (it updates automatically as you scroll)
Unrelated but I find it quite cool.

1 Like

Thanks again for so much help

excludedDates=[x for x in theSixtyDates if x not in datesFromQuery ]

I was able to produce this code today.

1 Like

I got stuck yesterday with a custom property that I bound to a tag history.
My ugly code workaround:

value=(currentVal[0][1])+(currentVal[0][6])+(currentVal[0][11])+(currentVal[0][16])+(currentVal[0][21])+(currentVal[0][26])+(currentVal[0][31])+(currentVal[0][36])+(currentVal[0][41])+(currentVal[0][46])+(currentVal[0][51])+(currentVal[0][56])+(currentVal[0][61])+(currentVal[0][66])

I got every 5th

x=range(71)
grossIndexes=x[1::5]

I just finished reading the thread over again to see if I could figure it out.
I have checked sites online

y=[[1,2],[3,4],[5,6],[1,1]]
print y[0][1]

How do I make something like currentVal in the script console for testing?
currentVal has 1 row, and 71 columns that start with one timestamp.

How would I pythonically sum and iterate through the currentVal columns?

You’re very close. :slight_smile:
Based on what you have, I’m assuming this is a PyDataSet. Let me know if I’m off.

x = range(71)

# Mock up some values
headers = ['col{}'.format(idx) for idx in x]
data = [[100 + idx for idx in x]]

# Make a dataset and a PyDataSet to play with
datasetIn = system.dataset.toDataSet(headers, data)
currentVal = system.dataset.toPyDataSet(datasetIn)

# You figured how to get every fifth starting with 1
grossIndexes=x[1::5]

# You can do the same thing with currentVal
grossValues = currentVal[0][1::5]

#Or, to sum it all up in one go
summedVal = sum(currentVal[0][1::5])
 
print grossValues
print summedVal
1 Like

Thank you, I am very upset I didn't realize this.


@JordanCClark
I am doing something wrong in my testing.

input

y=[[1,2],[3,4],[5,6],[1,1]]
sumY=sum(y[0][::2])
test =[y[0][::1]]
print sumY
print test

output

1
[[1, 2]]

Oh I see, row 0 is [1,2]

1 Like

Just so I’m on the same page, your “first” post intimated data like [[0,1,2,3,4,5,6,1,1]]. If it’s really [[1,2],[3,4],[5,6],[1,1]], then we’ll need to switch it up a bit. :slight_smile:

1 Like

I am getting an error trying to upload an image of my test.

I am getting an error that says row sequence must be integer or string.

when I write
value=sum(currentVal[0][1::5])

in my script on the pydataset currentVal.

Oh, wait. You’re still at 8.1.0, right? No upgrade yet? There were later changes to make pyDataSets more friendly. I think you may have to coerce it to a list. Been a while since I’ve had to think about it. lol

Try something like:
print list(currentVal[0])
If it works, then put the slice after it.
value=sum(list(currentVal[0])[1::5])

1 Like

why does value=sum(list(currentVal[0])[1::5])
work?

I don't understand that at all. currentVal[0] isn't anything is it?
I also don't know how to test print from a script I am running that isn't in the script console.

That’s part of why changes were made. :wink:

The datatype of the row is DatasetUtilities.PyDataSet.PyRow, which (IIRC) you could only reference from a single integer index or the column name. A slice, like [1::5], was not allowed.
EDIT: It’s also why your ‘ugly’ code worked, because you were referencing individual elements.
Turning the row into a list lets us be a bit more flexible.

If you’re in the designer, using print, or systyem.perspective.print() if you’re designing in Perspective will print to the designer console (Tools → Console).

1 Like

The other spot I got stuck a bit was in expression language.

Is it possible to benefit from list comprehensions in expression language?
I had setup an expression tag. I don’t think there is a script tag, except working from one tag, to write to a memory tag.

Or in later versions, are there script tags?

No, expressions are not python. List comprehensions are part of the python language.

1 Like
currentVal = system.dataset.toPyDataSet(value)
net=list(currentVal[0])[2::5]
eff=list(currentVal[0])[5::5]
totals=[a/b for a,b in zip(net,eff)]

How do I work around the dividing by zero error?

net= [1,   2,   3, 0, 4]
eff =[.5, 0.75, 0, 1, 3]
totals=[(a)/(b) for a,b in zip(net,eff)]

I thought this would work:
totals=[a/b if b!=0 else 0 for a,b in zip(net,eff) ]
I get nothing, and I am not sure why

You can call custom functions in a list comprehension so maybe like

def divideHandleZero(a, b):
    try:
        return a/b
    except ZeroDivisionError:
        return 'some value you want when you divide by zero'

net= [1,   2,   3, 0, 4]
eff =[.5, 0.75, 0, 1, 3]
totals=[divideHandleZero(a, b) for a,b in zip(net,eff)]
2 Likes

This worked, I forgot to type a print line.

1 Like

Yea I was going to say say that should have worked.

That list comprehension is about the limit for me in terms of putting logic into a single line, if you need anything more complicated I’d recommend making a custom function and calling it inside your list comprehension. Especially if you think there may be other usages of it elsewhere in your program.

1 Like

FYI, I think the convention would be to write that like

totals = [a/b for a,b in zip(net,eff) if b != 0]

The reason is, because this more clearly shows what is being inserted into the list.

You could also do this, which some may think is less readable. if b will only return False if b is 0.

totals = [a/b for a,b in zip(net,eff) if b]
3 Likes
totals=[a/b  for a,b in zip(net,eff) if b!=0 else 0]

This throws the error that ‘b’ is not defined.
I usually see if statements at the end in other comprehensions people showed me though.

if an else statement is needed, you’ll need to change up the order.

totals = [a/b if b != 0 else 0 for a,b in zip(net,eff)]

The difference is in the operation. An ‘if’ at the end checks after the calculation is done.
EDIT2: Not completely sure on the overall operation, as removing the else at the end of the line gives all values where b != 0

EDIT: This might get to the edge of readability, though.

1 Like