python - is this a valid for in loop? - python

I want to access the object, i.e. array[i], as well as the interator count, i.
This is what I'm trying:
for i, pinName in allPorts[startIndex:endIndex]:
#do stuff
I get errors further down, just wondering if it's this part of the code.
New to python here. Cheers.

I guess you rather are looking for:
for i, pinName in enumerate(allPorts[startIndex:endIndex]):
...
the enumerate() builtin takes any list (tuple, iterable, ...) and yields tuples of (index, item) with index starting at 0.

Consider enumerate() which returns a tuple with the index value and element:
startIndex = 2
endIndex = 4
for i, pinName in enumerate(allPorts[startIndex:endIndex], startIndex):
print('index = {} element = {}'.format(i, pinName))
yields:
index = 2 element = 66
index = 3 element = 99
Note the starting index value specified as 2nd parameter in enumerate() otherwise it will always start with index 0 (ignoring your startIndex, unless you always want to start with 0).

I suspect this is what you're thinking of:
for i, pinName in enumerate(allPorts[startIndex:endIndex]):
#do stuff
However, I don't think this will do what you expect. allPorts[startIndex:endIndex] will "slice" the list and create a new one, so allPorts[i] will still give the wrong index if startIndex != 0
If you need i to be the index in the original allPorts, then offhand I think this is what you'll have to do:
i = startIndex
while i < endIndex:
pinName = allPorts[i]
#do stuff
i += 1
As suggested in the comments, here's a much better way to do it:
for i in xrange(startIndex, endIndex):
pinName = allPorts[i]
#do stuff

Related

How to handle operating on items in a list without perfectly even len()?

I'm trying to operate on every 5 items in a list, but can't figure out how to handle the remaining items if they don't divide evenly into 5. Right now I'm using modulo, but I can't shake the feeling it's not quite the right answer. Here's an example...
list = ["ValA","ValB","ValC","ValD","ValE","ValF","ValG","ValH","ValI","ValJ","ValK","ValL","ValM","ValN",]
newlist = []
i = 0
for o in list:
i += 1
newlist.append(o)
if i % 5 == 0:
for obj in newlist:
function_for(obj)
newlist.clear()
This code will execute function_for() twice, but not a third time to handle the remaining 4 values. If I add an 'else' statement it runs on every execution.
What's the correct way to handle a situation like this?
This way is pretty easy, if you don't mind modifying the list:
mylist = ["ValA","ValB","ValC","ValD","ValE","ValF","ValG","ValH","ValI","ValJ","ValK","ValL","ValM","ValN",]
while mylist:
function_for( mylist[:5] )
mylist = mylist[5:]
You can also check if the index is equal to the length of the list. (Additionally, it is more idiomatic to use enumerate instead of a counter variable here.)
lst = ["ValA","ValB","ValC","ValD","ValE","ValF","ValG","ValH","ValI","ValJ","ValK","ValL","ValM","ValN",]
newlist = []
for i, o in enumerate(lst, 1):
newlist.append(o)
if i % 5 == 0 or i == len(lst):
print(newlist)
newlist.clear()

Python - Use certain position in list as a condition to trigger something else

I'm trying to think of a way to use a certain index of a list as a condition to trigger something else in python.
For example:
for val in mylist:
do something with val (the actual list entry)
if len(mylist)>= 4 and val has position 2 or bigger in mylist:
do something else
It's important that the if loop remains valid from position 2 until the end of mylist.
what would be a pythonic way to do this?
for i, val in enumerate(my_list):
do_something # will do this always
if i >= 2:
do_also_something_else # will be executed only when index is 2 or greater

Why my 2nd method is slower than my 1st method?

I was doing leetcode problem No. 387. First Unique Character in a String. Given a string, find the first non-repeating character in it and return it's index. If it doesn't exist, return -1.
Examples:
s = "leetcode"
return 0.
s = "loveleetcode",
return 2.
I wrote 2 algorithm:
Method 1
def firstUniqChar(s):
d = {}
L = len(s)
for i in range(L):
if s[i] not in d:
d[s[i]] = [i]
else:
d[s[i]].append(i)
M = L
for k in d:
if len(d[k])==1:
if d[k][0]<M:
M = d[k][0]
if M<L:
return M
else:
return -1
This is very intuitive, i.e., first create a count dictionary by looping over all the char in s (this can also be done using one line in collections.Counter), then do a second loop only checking those keys whose value is a list of length 1. I think as I did 2 loops, it must have some redundant computation. So I wrote the 2nd algorithm, which I think is better than the 1st one but in the leetcode platform, the 2nd one runs much slower than the 1st one and I couldn't figure out why.
Method 2
def firstUniqChar(s):
d = {}
L = len(s)
A = []
for i in range(L):
if s[i] not in d:
d[s[i]] = i
A.append(i)
else:
try:
A.remove(d[s[i]])
except:
pass
if len(A)==0:
return -1
else:
return A[0]
The 2nd one just loop once for all char in s
Your first solution is O(n), but your second solution is O(n^2), as method A.remove is looping over elements of A.
As others have said - using list.remove is quite expensive... Your use of collections.Counter is a good idea.
You need to scan the string once to find uniques. Then probably what's better is to sequentially scan it again and take the index of the first unique - that makes your potential code:
from collections import Counter
s = "loveleetcode"
# Build a set of unique values
unique = {ch for ch, freq in Counter(s).items() if freq == 1}
# re-iterate over the string until we first find a unique value or
# not - default to -1 if none found
first_index = next((ix for ix, ch in enumerate(s) if ch in unique), -1)
# 2

Negative number finder in index and occuring

Write a func/on first_neg that takes a (possibly empty) list of
numbers as input parameter, finds the first occurrence of a
nega/ve number, and returns the index (i.e. the posi/on in the
list) of that number. If the list contains no nega/ve numbers or it
is empty, the program should return None. Use while loop (and
not for loop) and your while loop should stop looping once the
first nega/ve number is found.
This is the question my teacher asked me any ideas this what i did:
def first_neg(list):
count = 0
for number in list:
if number < 0:
count += 1
return count
Dosent seem to work properly i just joined 1st post hope can get some help
x = [1,2,3,-5]
def first_neg(list):
count = 0
for number in list:
count += 1 #moved it outside of the if
if number < 0:
return count
print(first_neg(x)) #prints 4
You want to increment count not when you've found the answer but everytime the forloops loops. Note that this method returns 4 which is the fourth item in the list, not the index, Index of the list starts from 0 so to access it would be 3. Take our list x = [1,2,3,-5], -5 is in the fourth slot of the list, but to access it we have to call x[3] since lists starts at 0 indexing.
If you want to return the index of the list where the first negative number is found try this:
x = [1,2,3,-5]
def first_neg(list):
for count, number in enumerate(list):
if number < 0:
return count
print(first_neg(x)) # prints 3
This is because enumerate creates a "pairing" of the item in the list and it's the current count. Enumerate just counts from 0 everytime it gets an item out of the list.
Also as a side note ( I didn't change it in my answer since I wanted you to understand what's going on ). Don't name your variables keywords like list, tuple, int, str... Just a bad idea and habit, it works as you can see but it can cause issues.
Return the index immediately once you encounter the negative element. Increment the index otherwise:
def first_neg(lst):
count = 0
while count < len(lst):
if lst[count] < 0:
return count
count = count + 1
return None
Note : Better if you use enumerate() rather than using extra count variable. The code you mentioned is not written in pythonic way.
You may try this as well:
def first_neg(lst):
res = [i for i,x in enumerate(lst) if x<0]
return None if res == [] else res[0]
The code above can be improved using generators as suggested by #Chris_Rands.

What is the correct loop range

I want to delete some array from list. But I'm using wrong range.
At start the range is correct.
This should work, if string in variable result[b][2:3] then delete result[b]
for b in range(len(result)):
if 'FillLevel' in result[b][2:3]:
del result[b]
After that I have error: IndexError: list index out of range
I want to find this string and delete whole line (array):
V;4;FillLevel[1];CPUA.DB1610.0,I0,64;RW
V;4;FillLevel[2];CPUA.DB1610.0,I;RW
V;4;FillLevel[5];CPUA.DB1610.6,I;RW
V;4;FillLevel[6];CPUA.DB1610.8,I;RW
V;4;FillLevel[11];CPUA.DB1610.18,I;RW
Why this code:
print(result[4][2:3])
print(result[5][2:3])
print(result[6][2:3])
print(result[7][2:3])
print(result[8][2:3])
print(result[9][2:3])
print(result[10][2:3])
b = 0
while b < len(result):
if 'FillLevel' in result[b][2:3]:
del result[b]
del adress[b]
print('yes')
b += 1
Showing only once 'yes' ?
['FillLevel']
['FillLevel[1]']
['FillLevel[2]']
['FillLevel[3]']
['FillLevel[4]']
['FillLevel[5]']
['FillLevel[6]']
yes
The issue is that del result[b] changes the composition (and the length of) result, thereby interfering with your loop.
Perhaps the easiest way to fix this is by rephrasing your code as a list comprehension:
result = [r for r in result if 'FillLevel' not in r[2:3]]
Alternatively, you could fix it by iterating in reverse:
for b in range(len(result) - 1, -1, -1):
if 'FillLevel' in result[b][2:3]:
del result[b]
Let's say there are 10 items in the list.
Half-way through you delete one of the items; now there are 9 items in the list.
In the last cycle, your loop asks for the tenth item. My guess is that's where the index error is happening (though it could be due to the [2:3] call as well, depending on the contents of your list)
A more pythonic solution would be
result = [val for val in result if 'FillLevel' not in val[2:3]]
If you want to preserve the same list and parse it in the strait order you can use a while loop which evaluate the len(result) in each iteration
b = 0
while b < len(result) :
if 'FillLevel' in result[b][2:3]:
del result[b]
b += 1
for first
- it's mach easyer to iterate by list withot getting length, probably you are got an error coz length of list is changing during loop
for second
- you are trying to check 'FillLevel' in slice of string. slice return one character
- try to not midify your list but make new one with filtered items
like this:
new_list = []
for b in result:
if 'FillLevel' not in b:
new_list.append(b)
or check about List Comprehensions and type this:
[i for i in result if 'FillLevel' not in i]

Categories