python group multiple similar if statement - python

How to group a large amount of similar if else statement or is writing like the following good practice?
if len(G72List) > 1 and G72List[1] != "":
G7201Value = G72List[1]
else:
G7201Value = ""
if len(G72List) > 5 and G72List[5] != "":
G7205Value = G72List[5]
else:
G7205Value = ""
if len(G72List) > 6 and G72List[6] != "":
G7206Value = G72List[6]
else:
G7206Value = ""
if len(G72List) > 7 and G72List[7] != "":
G7207Value = G72List[7]
else:
G7207Value = ""
if len(G72List) > 8 and G72List[8] != "":
G7208Value = G72List[8]
else:
G7208Value = ""
if len(G72List) > 9 and G72List[9] != "":
G7209Value = G72List[9]
else:
G7209Value = ""
if len(G72List) > 10 and G72List[10] != "":
G7210Value = G72List[10]
else:
G7210Value = ""

A series of variable names that differ only by number can be refactored into a dict (or possibly a list if you're starting at 0 and incrementing by 1). Then the repetition can be factored out into a for loop.
GValue = {}
for i in [1, *range(5, 11)]:
if len(G72List) > i and G72List[i] != "":
GValue[7200+i] = G72List[i]
else:
GValue[7200+i] = ""

I've found this way to demo what you could do:
from contextlib import suppress
G7201Value = G7205Value = G7206Value = G7207Value = G7209Value = G7210Value = 'empty'
for i in range(12):
G72List = [_ for _ in range(i)]
print(G72List)
with suppress(IndexError):
G7201Value = G72List[1]
G7205Value = G72List[5]
G7206Value = G72List[6]
G7207Value = G72List[7]
G7208Value = G72List[8]
G7209Value = G72List[9]
G7210Value = G72List[10]
print(
G7201Value,
G7205Value,
G7206Value,
G7207Value,
G7209Value,
G7210Value
)
Output:
$ python3 g27.py
[]
empty empty empty empty empty empty
[0]
empty empty empty empty empty empty
[0, 1]
1 empty empty empty empty empty
[0, 1, 2]
1 empty empty empty empty empty
[0, 1, 2, 3]
1 empty empty empty empty empty
[0, 1, 2, 3, 4]
1 empty empty empty empty empty
[0, 1, 2, 3, 4, 5]
1 5 empty empty empty empty
[0, 1, 2, 3, 4, 5, 6]
1 5 6 empty empty empty
[0, 1, 2, 3, 4, 5, 6, 7]
1 5 6 7 empty empty
[0, 1, 2, 3, 4, 5, 6, 7, 8]
1 5 6 7 empty empty
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1 5 6 7 9 empty
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
1 5 6 7 9 10
Simple but efficient ;-)
Let me explain:
You where trying to see if the list was long enough, then checking if the value at the index you where looking to extract from had a value, then assign it, or set the value to "". you do not need to do this, you can just initialise the variables all at once with an empty string.
After, using contextlib.suppress(IndexError), allows the section of code indented after suppress to proceed as long as IndexError is not raised ;-)
Disclaimer:
for i in range(12):
G72List = [_ for _ in range(i)]
print(G72List)
was just for the purpose of the demo, to show you the behaviour with a list of various lenght.

Related

Adding condition in list in python

I don't know how to add extra conditions to this code.
(Only using randint)
For example with list [1, 2, 3, 4, 0] I need to generate random number except the last one (covered in my code) but the next condition is, it can not choose an index number which has a value of 0. So for list [3, 3, 0, 3, 3, 7] it can only consider indexes 0,1,3,4 (not 2 and 5 because I can not include the last number and index with value 0).
My code so far:
import random
our = [2, 3, 4, 0]
random_index = random.randint(0, len(our)-2)
random_number = our[random_index]
print(random_number)
I will be very glad for any help.
You can create a second list that stores the valid index values.
import random
our = [3, 3, 0, 3, 3, 7]
index = []
for i in range(0, len(our)-1) :
if our[i] != 0 :
index.append(i)
# index: [0, 1, 3, 4]
random_index = random.choice(index)
EDIT: You can perform a sanity check for a non-zero value being present.
The any() function returns True if any element of an iterable is True. 0 is treated as False and all non-zero numbers are True.
valid_index = any(our[:-1])
if valid_index:
index = []
for i in range(0, len(our)-1) :
if our[i] != 0 :
index.append(i)
You can use a while loop to check if the number equals 0 or not.
import random
our = [3, 6, 2, 0, 3, 0, 5]
random_number = 0
while random_number == 0:
random_index = random.randint(0, len(our)-2)
random_number = our[random_index]
print(random_number)

How to control which function is applied as values are iterated over, given changes of a corresponding variable

This is really just a simple logic question, but I provide a concrete example.
By 'corresponding' variable, I mean a variable that is understood to be related to the underlying data, although the value of the variable is not important for my question, just the fact the variable changes is important.
The code below generates the lists...
A = [2, 2, 2, 3, 2, 3]
B = [3, 3, 3, 2, 3, 2]
...by responding to a change in the values in the 'slope' list. But, actually this should be...
A = [2, 2, 2, 3, 2, 2]
B = [3, 3, 3, 2, 3, 3]
What is the logic required to correct this?
def funcOne(val):
return val + 1
def funcTwo(val):
return val + 2
values = [1, 1, 1, 1, 1, 1]
slope = [1, 1, 1, -1, -1, 1]
A = []
B = []
l = len(values)
for i in range(l-1):
val = values[i]
sign = slope[i]
pre = slope[i-1]
nex = slope[i+1]
if pre == sign:
va = funcOne(val)
vb = funcTwo(val)
A.append(va)
B.append(vb)
if nex != sign:
va = funcOne(val)
vb = funcTwo(val)
A.append(vb)
B.append(va)
print(A)
# target list:
# [2, 2, 2, 3, 3, 2]
print(B)
# target...
# [3, 3, 3, 2, 2, 3]
try this
#!/usr/bin/python3
def funcOne(val):
return val + 1
def funcTwo(val):
return val + 2
values = [1, 1, 1, 1, 1, 1]
slope = [1, 1, 1, -1, -1, 1]
A = []
B = []
l = len(values)
for i in range(l-1):
val = values[i]
sign = slope[i]
pre = slope[i-1]
nex = slope[i+1]
if sign == pre:
va = funcOne(val)
vb = funcTwo(val)
A.append(va)
B.append(vb)
if pre > nex:
va = funcOne(val)
vb = funcTwo(val)
A.append(vb)
B.append(va)
print(A)
# target list:
# [2, 2, 2, 3, 3, 2]
print(B)
# target...
# [3, 3, 3, 2, 2, 3]
Now I have a working solution I see in fact the correct behaviour would result in the lists
A = [2, 2, 2, 3, 2, 2], and
B = [3, 3, 3, 2, 3, 3].
This has been corrected in the original post.
Overall, irrespective of the exact behaviour required, I have found that a solution to this problem is to create and update a variable that represents which function was applied in the previous step (in this case simply a boolean called 'check'), to evaluate against whether the sign of the corresponding variable ('slope') is positive, negative or zero, and to evaluate against whether or not the corresponding variable is the same as in the previous step.
I feel like there must still be a more concise way of expressing this solution so additional comments are welcomed.
#!/usr/bin/env python3
def funcOne(val):
return val + 1
def funcTwo(val):
return val + 2
values = [1, 1, 1, 1, 1, 1]
slope = [1, 1, 1, -1, -1, 1]
A = []
B = []
l = len(values)
check = True
#for i in range(l-1):
for i in range(l):
val = values[i]
sign = slope[i]
pre = slope[i-1]
va = funcOne(val)
vb = funcTwo(val)
if sign == pre and check == True:
A.append(va)
B.append(vb)
check = True
if sign == pre and check == False:
A.append(vb)
B.append(va)
check = False
if sign != pre and sign > 0 and check == True:
A.append(va)
B.append(vb)
check = True
if sign != pre and sign > 0 and check == False:
A.append(vb)
B.append(va)
check = False
if sign != pre and sign < 0 and check == True:
A.append(vb)
B.append(va)
check = True
if sign != pre and sign < 0 and check == False:
A.append(va)
B.append(vb)
check = False
if sign != pre and sign == 0 and check == True:
A.append(va)
B.append(vb)
check = True
if sign != pre and sign == 0 and check == False:
A.append(vb)
B.append(va)
check = False
print(A)
# [2, 2, 2, 3, 2, 2]
print(B)
# [3, 3, 3, 2, 3, 3]

How to ignore numbers after specific number in the list/array in Python?

I'm stuck on this problem:
I was trying to return sum of list of numbers in the array ignoring sections of numbers starting with a 6 and extending to the next 9 (every 6 will be followed by at least one 9). Return 0 for no numbers.
Here are my test cases:
number_69([1, 3, 5]) --> 9
number_69([4, 5, 6, 7, 8, 9]) --> 24
number_69([2, 1, 6, 9, 11]) --> 14
I came up with something like:
def number_69(arr):
for num in arr:
if 6 not in arr and 9 not in arr:
return sum(arr)
return 0
i guess we stop adding when we see 6 and we start again when we see 9
def number_69(arr):
sum = 0
stop = False
for num in arr:
if num == 6:
stop = True
elif num == 9:
stop = False
elif stop is False:
sum = sum + num
return sum
print(number_69([2, 1, 6, 9, 11]))
Great name for a function BTW
def summer_69(arr):
toSum = True
sum = 0
for x in arr:
if toSum :
if(x == 6):
toSum = False
else :
sum += x
else :
if(x == 9):
toSum = True
return sum
Hope it is useful
Another attempt, using list.pop:
lst = [4, 5, 6, 7, 8, 9]
def summer_69(lst):
s = 0
while lst:
i = lst.pop()
if i == 9:
while i!=6:
i = lst.pop()
else:
s += i
return s
print(summer_69(lst))
Prints:
9
You can iteratively slice out the parts between the 6 and the 9 until there are no more pairs, then call sum on the remainder.
For 'slicing' we use the Python's index slicing, which works by giving a start index and an end index (which will not be included).
>>> [0, 1, 2, 3][1:3] == [1, 2]
True
>>> [0, 1, 2, 3][1:]
[1, 2, 3]
>>> [0, 1, 2, 3][:2]
[0, 1]
We find the locations of the first 6 and the first following 9 with list.index. We do have to make sure to only start looking for a 9 after the 6. This gives
def number_69(arr):
while 6 in arr:
index = arr.index(6)
arr = arr[:index] + arr[index + arr[index:].index(9) + 1:]
# +index because we are removing it from arr[index:]
# +1 because we don't want to include the 9 in the new list
return sum(arr)
Since we know that every 6 will be followed by a 9, there is no need to check whether there is a 9 in the list. Thus, this function will remove all 6-9 blocks and only then return the sum of the entire list.
If there is a 6 without an accompanying 9 this function will raise a ValueError. This can be solved by checking for a 9 anyways, but this has to be done after the index of the first 6. If no 9 is found, we also have to break out of the loop, since the 6 will not be removed.
def number_69(arr):
while 6 in arr:
index = arr.index(6)
if 9 in arr[index:]:
arr = arr[:index] + arr[index + arr[index:].index(9) + 1:]
# +index because we are removing it from arr[index:]
# +1 because we don't want to include the 9 in the new list
else:
break
return sum(arr)
def summer_69(arr):
pop = []
for i in arr:
if i <=9 and i>=6:
continue
else:
pop.append(i)
return pop

List index out of range and i got error in my if block which is inside the while loop

def merge(a1,a2):
if len(a1)<1:
return a2
if len(a2)<1:
return a1
a1item=a1[0]
a2item=a2[0]
i=1
j=1
merge=[]
while(a1item or a2item):
print(a1item,a2item)
if a1item<a2item:
merge.append(a1item)
a1item=a1[i]
i+=1
else:
merge.append(a2item)
a2item=a2[j]
j+=1
print(merge)
merge([1,2,3],[3,54,100])
I got error in a1item=a1[i] how to stop when the loop is pointing to last element.
Suggest me without using inbuilt function
You need to check your bounds yourself - beside that you got another error bound to happen if you merge [0,1,2,3] and [0,4,8] :
while(0 or 0):
is falsy and your function will not enter the while loop.
Fixes with comments:
def merge(a1,a2):
if len(a1)<1:
return a2
if len(a2)<1:
return a1
i=0
j=0
# store result once - micro-optimization
la1 = len(a1)
la2 = len(a2)
m=[] # do not call variables the same as the function, in case you want to recurse
# I removed the variables to hold the current values in favor
# of directly indexing them
while True: # beware of (0 or 0) which is falsy
print(a1[i],a2[j],end=" -> ")
if a1[i] <= a2[j]: # one more "true" value in first if branch
m.append(a1[i]) # if both are same, we take from the 1st list
i+=1 # no need to branch into the else part
else:
m.append(a2[j])
j+=1
print(m)
# stop conditions: if one list is done, add the other to the end of m
if i == la1:
m.extend(a2[j:])
break
if j == la2:
m.extend(a1[i:])
break
return m
print("----",merge([1,6,9],[0,7,8,11]))
Output:
1 0 -> [0]
1 7 -> [0, 1]
6 7 -> [0, 1, 6]
9 7 -> [0, 1, 6, 7]
9 8 -> [0, 1, 6, 7, 8]
9 11 -> [0, 1, 6, 7, 8, 9]
---- [0, 1, 6, 7, 8, 9, 11]
You can read more about list slicing here: Understanding slice notation

How do I remove a range (subsection) of a list in Python?

I have a simple, always-consecutive-ordered list like this:
all = [ 1, 2, 3, 4, 5, 6 ] # same as range( 1, 7 )
I also have current = 4. In the end I want the all list to look like this
altered = [ 1, 2, 5, 6 ]
So what happened was it removed the current number and the one before it 3.
current can also be 1 and 0, so I want to make sure it doesn't throw an error for those two values.
For the exception current = 0, the altered list is like this
altered = [ 1, 2, 3, 4, 5 ]
Which means that current = 0 simply removes the last number.
I feel like you can probably code something fancy with generators, but I suck at writing them.
Thanks in advance!
Bonus points for doing this in one line. If the current = 0 is too much trouble, then it could also be current = -1 or current = 7.
EDIT: Make sure to check for current = 1, which should be
altered = [ 2, 3, 4, 5, 6 ]
all = all[:max(current - 2, 0)] + all[current:]
or
del all[max(current - 2, 0):current]
Would this work?
>>> all = range(1, 7)
>>> new = all[:2]+all[4:]
>>> print new
[1, 2, 5, 6]
all[:max(current-2,0)] + all[max(current,0):][:-1] + all[-1:]*(0 < current < len(all))
>>> all = range(1,7)
>>> current = 4
>>> [item for item in all if item != current and item != current-1]
[1, 2, 5, 6]
>>> current = 0
>>> [item for item in all if item != current and item != current-1]
[1, 2, 3, 4, 5, 6]

Categories