Python List Comprehensions Help

Omit it altogether or return None? I ask, because how would you know which was which if it’s missing from the output.

EDIT: Or is at a summary, as @lrose just posted?

1 Like

It is a summary as @lrose posted.

I think I put the code with the grouper def in wrong for testing. I got zero.
I also don’t understand a couple parts of the code that I will ask about.

I think I should learn to get the nested list for this input and output:

input:

infeed=[1000,2000,3000,0,5000,90]
outfeed=[1001,2001,0,4001,91,6001]
param3=[1.12,1.22,1.32,0,1.52,1.62]
param4=[3.1,3.2,3.3,3.4,3.5,3.6]
param5=[104,204,304,404,504,604]
bigList= zip(infeed, outfeed, 
param3,param4,param5)

print bigList

Desired output:

[0.99,0.99]

I am getting no viable alternative for “if” as an error.

test=[[a[0]/a[1] if a[0]>100 and a[1]>100 for a in b]  for b in bigList]

and

test=[a[0]/a[1] if (a[0]>100 and a[1]>100) for a in bigList]

Ok,. if there is no ‘else’ statement, the if clause needs to go on the end. Also, dividing ints truncates the result. One of your values needs to be a float.

Combining the grouper recipe:


def grouper(n, iterable):
	return zip(*[iter(iterable)] * n)

#################
# Usage example #
#################

vals = [system.date.parse('2022-08-18 12:34:56'),
        1000, 1001, 1.12, 3.1, 104,
        2000, 2001, 1.22, 3.2, 204,
        3000,    0, 1.32, 3.3, 304,
           0, 4000,    0, 3.4, 404,
        5000,   91, 1.52, 3.5, 504,
          90, 6001, 1.62, 3.6, 604
       ]

groupedVals = grouper(5, vals[1:])

# You can print this, but it just shows the object.

print [float(x[0])/x[1]  for x in groupedVals if (x[0]>=100 and x[1]>100)]

Output:

[0.999000999000999, 0.9995002498750625]
>>> 
1 Like

ahhhhh
Thanks

I can’t believe that I got hung on the “if” statement being at the end.
I kept thinking I had to use a nested list.
I didn’t even realize what the error code was saying till you said it too.
Thanks so much.

This is my current direction I am going.
After I finish, then I want to circle back and learn the code that @lrose posted.
I appreciate the help with this stuff.

infeed=[1000,2000,3000,0,5000,90]
outfeed=[1001,2001,0,4001,91,6001]
param3=[1.12,1.22,1.32,0,1.52,1.62]
param4=[3.1,3.2,3.3,3.4,3.5,3.6]
param5=[104,204,304,404,504,604]
bigList= zip(infeed, outfeed, 
param3,param4,param5)

print bigList
test=[float(a[0])/a[1]  for a in bigList if a[0]>100 and a[1]>100]
#test= "{:.1%}".format(test)
print test
#desired output [almost 1, almsot 1]

bigList=[a for a  in bigList if (a[0]>100 and a[1]>100)]
print bigList

qual=[ float(a[0])/a[1] for a in bigList]
print qual	

>>> 
[(1000, 1001, 1.12, 3.1, 104), (2000, 2001, 1.22, 3.2, 204), (3000, 0, 1.32, 3.3, 304), (0, 4001, 0, 3.4, 404), (5000, 91, 1.52, 3.5, 504), (90, 6001, 1.62, 3.6, 604)]
[0.999000999000999, 0.9995002498750625]
[(1000, 1001, 1.12, 3.1, 104), (2000, 2001, 1.22, 3.2, 204)]
[0.999000999000999, 0.9995002498750625]
>>>

update

vals = system.dataset.toPyDataSet(value)
		
infeed=		list(vals[0])[1::5]	
outfeed=	list(vals[0])[2::5]	
uptime=		list(vals[0])[3::5]
downtime=	list(vals[0])[4::5]
maxV=		list(vals[0])[5::5]	
bigList= zip(infeed,outfeed,uptime,downtime,maxV)
	
bigList=[a for a  in bigList if (a[0]>100 and a[1]>100)]
infeed=		[ a[0] for a in bigList]	
outfeed=	[ a[1] for a in bigList]	
uptime=		[ a[2] for a in bigList]
downtime=	[ a[3] for a in bigList]
maxV=		[ a[4] for a in bigList]		

infeed=sum(infeed)
outfeed=sum(outfeed)	
rateXUptime=[a*b for a,b in zip(uptime,maxV)]
rateXUptime=sum(rateXUptime)	
uptime=sum(uptime)*1.0/60
downtime=sum(downtime)*1.0/60	
duration=uptime+downtime	
	
def handleDivideZero(a,b):
	return 0 if (a and b)==0 else a/b 
	
avail=	handleDivideZero(float(uptime),float(duration))
perf= 	handleDivideZero(float(infeed),rateXUptime)
qual=	handleDivideZero(outfeed,float(infeed))
	
#	value1=avail
#	value1=perf
#	value1=qual
#	value1=infeed
#	value1=outfeed
#	value1=uptime
#	value1=downtime
#	value1=rateXUptime
value="{:.1%}".format(avail*perf*qual)
return value	

It is easy for me to read, and I think it is easy to analyze too.
I can highlight the commented out values and ctrl+/ to uncomment them.
Then I can make ‘value1’ into ‘value’ to compare the values to check on the machines.

Thanks for the help!
I am very happy with the code.


@lrose had some things I want to learn about if possible in post 140.

I think zip(*[iter(iterable)] * n) is putting groups of N into a list of lists.
I read that ‘*’ can be used to get values from a list without the brackets and commas.
I read that ‘Iter()’ lets you call next() to get subsequent values to a limit they call a sentinel.
I don’t really understand that part because iter() is used on iterable, the variable that is the original list.
How does the *n outside impact *[iter(iterable)] ?
If I had ["hello world"]*3 then I would have ["hello world", "hello world", "hello world"]
I think this is a matter of python syntax which I don’t know.
I would have expected repetition of the same values on the order of n repetitions.

I did not know a dictionary could be used like Sums, at least I think that is a dictionary.
I think I understand that part and thankfully I think I get the rest of list comprehensions below that section.

2 Likes

The grouper function makes use of the single-pass nature of iterators.

To get n copies of the iterator, it's put into a list, them multiplied by n. Note that this makes a list of references to the same iterator object. Every time you grab a value from the iterator, it goes to the next value, regardless of which copy of the iterator does it.

The '*' at the beginning is so we can unpack the elements of the list of iterators. and zip can work properly.

A list of lists (testList) 
[['a', 'b', 'c'], [1, 2, 3]]

zip directly on list of lists
zip(testList)
[(['a', 'b', 'c'],), ([1, 2, 3],)]

zip after unpacking
zip(*testList)
[('a', 1), ('b', 2), ('c', 3)]

Here's a scipt to play with. Hopefully, it will give you some insight

vals = [
        1000, 1001, 1.12, 3.1, 104,
        2000, 2001, 1.22, 3.2, 204,
        3000,    0, 1.32, 3.3, 304,
           0, 4000,    0, 3.4, 404,
        5000,   91, 1.52, 3.5, 504,
          90, 6001, 1.62, 3.6, 604
       ]

iterator = iter(vals)

a, b, c, d, e = iterator, iterator, iterator, iterator, iterator

for i in xrange(6):
	print next(a), next(d), next(c), next(d), next(e)

print ''
print '-----------------------------------------------'
print ''
						
iterator2 = iter(vals)
iteratorList = [iterator2] * 5

for i in xrange(6):
	for x in iteratorList:
		print next(x),
	print ''

print ''
print '-----------------------------------------------'
print ''

iterator3 = iter(vals)
iteratorList = [iterator3] * 5
for x in zip(*iteratorList):
	print x

Output:

1000 1001 1.12 3.1 104
2000 2001 1.22 3.2 204
3000 0 1.32 3.3 304
0 4000 0 3.4 404
5000 91 1.52 3.5 504
90 6001 1.62 3.6 604

-----------------------------------------------

1000 1001 1.12 3.1 104 
2000 2001 1.22 3.2 204 
3000 0 1.32 3.3 304 
0 4000 0 3.4 404 
5000 91 1.52 3.5 504 
90 6001 1.62 3.6 604 

-----------------------------------------------

(1000, 1001, 1.12, 3.1, 104)
(2000, 2001, 1.22, 3.2, 204)
(3000, 0, 1.32, 3.3, 304)
(0, 4000, 0, 3.4, 404)
(5000, 91, 1.52, 3.5, 504)
(90, 6001, 1.62, 3.6, 604)
>>>
2 Likes
value2='bz'

excludes=['p','y','z']
color = ['#AAAAAA' if x not in value2 and 'b' in value2  else '#FFFFFF' for x in excludes]
print color[0]

Why is this printing #AAAAAA instead of #FFFFFF?

Because 'p' is not in 'bz' and 'b' is in 'bz'. What were you expecting?

2 Likes

I thought that x would be 'z' when iterating.

'z' is in 'bz'

I think I am using something exactly backwards haha.

It eventually is...

value2='bz'

excludes=['p','y','z']
color = ['#AAAAAA' if x not in value2 and 'b' in value2  else '#FFFFFF' for x in excludes]
for i in enumerate(zip(excludes, color)):
	print i

Output:

(0, ('p', '#AAAAAA'))
(1, ('y', '#AAAAAA'))
(2, ('z', '#FFFFFF'))
1 Like
value2='bhh'

excludes=['p','y','z']
result = [True if 'b' in value2 and x not in value2 else False for x in excludes]
color = '#AAAAAA' if all(result) else '#FFFFFF'
print color

Probably, I will do something like this.

Ok. It can be shortened a tad, since the comparison is already boolean.

color = [x not in value2 for x in excludes]

or, if you really want to go the one-line route:

color = all([x not in value2 for x in excludes])

Personally, I'd still keep them separate, as it makes for easier troubleshooting.

1 Like

Thanks

value2='bh'

excludes=['p','y','z']
result = ['b' in value2 and x not in value2 for x in excludes]
color = '#AAAAAA' if all(result) else '#FFFFFF'
print value2
print color

Now I can check the id of the view, and color my navigation text while the path can have some level of redundant strings.

1 Like

It seems weird to check every item in an 'exclude' list against a value, instead of the opposite...
Is it really what you want to do ?

I am not sure.

I need to check if the string contains one word and not five others to make an evaluation for sure.

So you want to check whether a particular string is in a list of pre-determined strings.
What you're doing with the code above is check whether those to-be-excluded strings match with your tested string, instead of checking if your tested string matches with one of the to-be-excluded strings.
Which actually makes a world of difference, particularly in how the code conveys what it's supposed to do.

def is_this_string_valid(test_string, required_words, forbidden_words):
	s = test_string.split()
	return all(w in s for w in required_words) and not any(w in forbidden_words for w in s)


req = ["foo", "qux"]
excl = ["bar", "baz"]

print(is_this_string_valid("foo", req, excl))
# > False
print(is_this_string_valid("foo qux", req, excl))
# > True
print(is_this_string_valid("foo qux bar", req, excl))
# > False
print(is_this_string_valid("foo qux bar baz", req, excl))
# > False
print(is_this_string_valid("bla foo something qux", req, excl))
# > True

Note that if you have only one required word, you can replace all(w in s for w in required_words) with required_word in s.
Note also that how you determine what a word is, is up to you. Here I just used whitespaces as delimitation between words. You might want to process things further.

2 Likes

I want to see if any values in a list are in a string I think.

I don't understand maybe.
What is the advantage of :

def is_this_string_valid(test_string, required_words, forbidden_words):
	s = test_string.split()
	return all(w in s for w in required_words) and not any(w in forbidden_words for w in s)


req = ["foo", "qux"]
excl = ["bar", "baz"]

print(is_this_string_valid("foo", req, excl))

over :

excludes=['p','y','z']
result = ['b' in value2 and x not in value2 for x in excludes]
color = '#AAAAAA' if all(result) else '#FFFFFF'

Well... I suggest you figure out exactly what you need/want before you start coding ;p

1 Like

Why do you say I don't know what I want or need?
Why do you talk to me like that?
I had posted code that did exactly what I meant it to do with Jordan's help.

What you're doing with the code above is check whether those to-be-excluded strings match with your tested string, instead of checking if your tested string matches with one of the to-be-excluded strings.
Which actually makes a world of difference, particularly in how the code conveys what it's supposed to do.

Can you explain this for me?
I don't understand what you mean here either.
I don't know the advantage.

I think it's mostly readability though there may be a slight performance increase with using python keywords, in the same way you use list comprehensions instead of a for loop, there's a slight performance increase.

But I think readability is the big deciding factor over what you prefer. That and putting it inside a function so you can call it anywhere is a big advantage over hardcoding it.

1 Like

That made me feel like you're not sure what your goal is. Sorry if I was rude, didn't mean to be.

One deals with words in strings, the other deals with characters.
Also, I find that using all() and any() makes it clear what is expected.

Actually your way was totally valid. I just find the logic kind of backwards - I'd tend to check if my string is in the list of strings to exclude, instead of checking if the strings to exclude match my string.

edit:
Here's a version that will handle characters, words, numbers, pretty much anything you throw at it, as long as values are in lists:

def is_this_list_valid(values, required_values=None, forbidden_values=None):
	req_check = True
	if required_values is not None:
		req_check = all(v in values for v in required_values)
	excl_check = True
	if forbidden_values is not None:
		excl_check = not any(v in forbidden_values for v in values)
	return req_check and excl_check


req = [42, 'foo', {'baz': "BAZ"}]
excl = ["bar", 21, 'a']

tests = [
	['bla', 42, 'b', 'foo', {'baz': "BAZ"}],
	['42', 'foo', 'baz'],
	[42, 'foo', 21]
]

for t in tests:
	print(is_this_list_valid(t, req, excl))
# > True
# > False
# > False

Might be simpler to just pass empty lists on call instead of using None as default, but... blah.

2 Likes