I am currently learning Python (I have a strong background in Matlab). I would like to write a loop in Python, where the size of the array increases with every iteration (i.e., I can assign a newly calculated value to a different index of a variable). For the sake of this question, I am using a very simple loop to generate the vector t = [1 2 3 4 5]. In Matlab, programming my desired loop would look something like this:
t = [];
for i = 1:5
t(i,1) = i;
end
I have managed to achieve the same thing in Python with the following code:
result_t = []
for i in range(1,5):
t = i
result_t.append(t)
Is there a more efficient way to assign values to an array as we iterate in Python? Why is it not possible to do t[i,1] = i (error: list indices must be integers or slices, not tuple) or t.append(t) = t (error: 'int' object has no attribute 'append')?
Finally, I have used the example above for simplicity. I am aware that if I wanted to generate the vector [1 2 3 4 5] in Python, that I could use the function "np.arange(1,5,1)"
Thanks in advance for your assistance!
-> My real intention isn't to produce the vector [1 2 3 4 5], but rather to assign calculated values to the index of the vector variable. For example:
result_b = []
b = 2
for i in range(1,5):
t = i + b*t
result_b.append(t)
Why can I not directly write t.append(t) or use indexing (i.e., t[i] = i + b*t)?
Appending elements while looping using append() is correct and it's a built-in method within Python lists.
However you can have the same result:
Using list comprehension:
result_t = [k for k in range(1,6)]
print(result_t)
>>> [1, 2, 3, 4, 5]
Using + operator:
result_t = []
for k in range(1,6):
result_t += [k]
print(result_t)
>>> [1, 2, 3, 4, 5]
Using special method __iadd__:
result_t = []
for k in range(1,6):
result_t.__iadd__([k])
print(result_t)
>>> [1, 2, 3, 4, 5]
The range function returns an iterator in modern Python. The list function converts an iterator to a list. So the following will fill your list with the values 1 to 5:
result_t = list(range(1,6)) # yields [1, 2, 3, 4, 5]
Note that in order to include 5 in the list, the range argument has to be 6.
Your last example doesn't parse unless you assign t a value before the loop. Assuming you do that, what you're doing in that case is modifying t each time through the loop, not just producing a linear range. You can get this effect using the map function:
t = 0
b = 2
def f(i):
global t
t = i + b*t
return t
result_b = list(map(f, range(1, 5))) # Yields [1, 4, 11, 26]
The map function applies the f function to each element of the range and returns an iterator, which is converted into a list using the list function. Of course, this version is more verbose than the loop, for this small example, but the technique itself is useful.
a better example from UI Testing using selenium.
print('Assert Pagination buttons displayed?')
all_spans = self.web_driver.find_elements_by_tag_name('span')
# Identify the button texts
pagination_buttons = ["Previous Page", "Next Page", "First Page"]
# Filter from all spans, only the required ones.
filtered_spans = [s for s in all_spans if s.text in pagination_buttons]
# From the filtered spans, assert all for is_displayed()
for a_span in filtered_spans:
assert a_span.is_displayed()
print('Asserted Pagination buttons displayed.')
You can try this
data = ['Order-'+str(i) for i in range(1,6)]
print(data)
>>> ['Order-1', 'Order-2', 'Order-3', 'Order-4', 'Order-5']
Related
I am trying to make a function that creates an array from the functions original array, that starts on the second element and multiplies by the previous element.
Example
input: [2,3,4,5]
output: [6,12,20]
I am trying to use a loop to get this done and here is my code so far
def funct(array1):
newarray = []
for x in array1[1:]:
newarray.append(x*array1)
return newarray
I am at a loss as I am just learning python, and i've tried various other options but with no success. Any help is appreciated
try
A = [2, 3, 4, 5]
output = [a*b for a, b in zip(A[1:], A[:-1])]
You can use a list comprehension like so:
inp = [2,3,4,5]
out = [j * inp[i-1] for i,j in enumerate(inp) if i != 0]
Output:
[6,12,20]
How can you loop across multiple different ranges. for example say i want to run a for loop for specific set of ranges
1 to 2, 4 to 6 and 10 to 13,
I don't know the exact final number so maybe a function might be useful.
The standard method of
for i in range(1,2) + range (4,6) + range (10,13)
I should have this
[1,4,5,6,10,11,13]
My question is, this is not so efficient, if i don't know the total number of ranges am covering, and I can't even create this as a function without so many parameters.
so if i want to have something like this
for i in range(a,b) + range (c,d) + range (e,f), .....
but as a simple function
Can someone help with an efficient way of doing this ?
Simple, though most likely the least efficient solution is to use a nested for loop,
def multi_range_loop(ranges):
all_values = []
for rg in ranges:
for i in range(rg[0], rg[1]):
all_values.append(i)
print(all_values)
my_ranges = [[1,3],[4,7],[10,14]]
multi_range_loop(my_ranges)
You can chain the ranges with itertools:
from itertools import chain
total_range = chain(range(1,2), range(4,6), range(10,13))
print(list(total_range))
#[1, 4, 5, 10, 11, 12]
Here is another solution with a function that returns a generator:
def total_range(lst):
return (i for tup in lst for i in range(tup[0], tup[1]))
list_of_ranges = [(1,2), (4,6), (10,13)]
print(list(total_range(list_of_ranges)))
To have an iterable object from the list of iterable form the different ranges you can use the chain function as in the following response https://stackoverflow.com/a/67547449/1287983.
And in order to have dynamic ranges in a function you can do the following:
def get_ranges(list_ranges):
lower_bounds, upper_bounds = zip(*list_ranges)
return list(chain(*list(map(
range, lower_bounds, upper_bounds))))
get_ranges([(1,2), (4,6), (10,13)])
[1, 4, 5, 10, 11, 12]
The function above returns the list of values. And if you want to iterate efficiently over the resulting values, you just need to return the iterator instead of the list. See the code below.
def get_ranges(list_ranges):
lower_bounds, upper_bounds = zip(*list_ranges)
return chain(*list(map(range, lower_bounds, upper_bounds)))
for val in get_ranges([(1,2), (4,6), (10,13), (2,5)]):
print(val)
1
4
5
10
11
12
2
3
4
I'm making a program that basically calculates the missing values (x in this example) in multiple lists.
These are the lists:
L11=[1,3,5,'x',8,10]
L12=['x',3,3,'x',6,0]
L21=[6,1,1,9,2,2]
L22=[1,1,1,'x','x','x']
For example, I'm using this code block to find the x values in L22:
#How to find x:
#1--> a= calculate the sum of integers in the list
#2--> b=calculate the average of them
#3--> all values of x inside the list equal b
a22=L22.count('x')
for i in range(len(L22)):
if L22[i]=='x':
x_L22=round((sum([int(k) for k in L22 if type(k)==int]))/(len(L22)-a22))
So we find x_L22=1 and the new L22 is:
x_L22=1
L22=[1,1,1,1,1,1]
Now here is my question, I want to repeat this steps for all other lists without writing the same code. Is this possible?
Other answers focus on extracting your current code to a generic function which is useful but isn't neither sufficient nor necessary to apply the same piece of code on multiple input.
The only thing you need is to loop over your pieces of data :
L11=[1,3,5,'x',8,10]
L12=['x',3,3,'x',6,0]
L21=[6,1,1,9,2,2]
L22=[1,1,1,'x','x','x']
inputs = ( L11, L12, L21, L22 )
for input in inputs :
# your 4 previous lines on code, modified to work
# on the generic "input" instead of the specific "L22"
a=input.count('x')
for i in range(len(input)):
if input[i]=='x':
x=round((sum([int(k) for k in input if type(k)==int]))/(len(input)-a))
# or if you've extracted the above code to a function,
# just call it instead of using the above 4 lines of code.
try putting it in a function like this:
def list_foo(list_):
counted=list_.count('x')
for i in range(len(list_)):
if list_[i]=='x':
total=round((sum([int(k) for k in list_ if type(k)==int])) \
/(len(list_)-counted))
return total
use it in your main loop
x_L22 = list_foo(L22)
or x_L11 = list_foo(L11)
This is an excellent use case for functions in Python
def get_filled_list(list_of_numbers):
#How to find x:
#1--> a= calculate the sum of integers in the list
#2--> b=calculate the average of them
#3--> all values of x inside the list equal b
new_list=list_of_numbers.count('x')
for i in range(len(list_of_numbers)):
if list_of_numbers[i]=='x':
list_of_numbers = round(
(sum([int(k)
for k in list_of_numbers if type(k)==int]))/
(len(list_of_numbers)-new_list)
)
A11 = get_filled_list(L11)
# ,..
I'd write a function that receives a list as an input and returns the same list with the 'x' value replaced with a new value:
def calculateList(l):
nrX=l.count('x')
newList = []
for elem in l:
if elem == 'x':
x = int(round((sum([int(k) for k in l if type(k)==int]))/(len(l)-nrX)))
newList.append(x)
else:
newList.append(elem)
return newList
You can then call this function on all the list you have:
newL = calculateList(L22)
print(newL)
Output is:
[1, 1, 1, 1, 1, 1]
Or if you prefer you can create a list containing all the lists you want to evaluate:
allLists = [L11, L12, L21, L22]
And then you iterate over this list:
for l in allLists:
newL = calculateList(l)
print(newL)
Output is:
[1, 3, 5, 5, 8, 10]
[3, 3, 3, 3, 6, 0]
[6, 1, 1, 9, 2, 2]
[1, 1, 1, 1, 1, 1]
I have this problem on writing a python function which takes a bit list as input and prints the items represented by this bit list.
so the question is on Knapsack and it is a relatively simple and straightforward one as I'm new to the python language too.
so technically the items can be named in a list [1,2,3,4] which corresponds to Type 1, Type 2, Type 3 and etc but we won't be needing the "type". the problem is, i represented the solution in a bit list [0,1,1,1] where 0 means not taken and 1 means taken. in another words, item of type 1 is not taken but the rest are taken, as represented in the bit list i wrote.
now we are required to write a python function which takes the bit list as input and prints the item corresponding to it in which in this case i need the function to print out [2,3,4] leaving out the 1 since it is 0 by bit list. any help on this? it is a 2 mark question but i still couldn't figure it out.
def printItems(l):
for x in range(len(l)):
if x == 0:
return False
elif x == 1:
return l
i tried something like that but it is wrong. much appreciated for any help.
You can do this with the zip function that takes two tiers Lee and returns them in pairs:
for bit_item, item in zip(bit_list, item_list):
if bit_item:
print item
Or if you need a list rather than printing them, you can use a list comprehension:
[item for bit_item, item in zip(bit_list, item_list) if bit_item]
You can use itertools.compress for a quick solution:
>>> import itertools
>>> list(itertools.compress(itertools.count(1), [0, 1, 1, 1]))
[2, 3, 4]
The reason your solution doesn't work is because you are using return in your function, where you need to use print, and make sure you are iterating over your list correctly. In this case, enumerate simplifies things, but there are many similar approaches that would work:
>>> def print_items(l):
... for i,b in enumerate(l,1):
... if b:
... print(i)
...
>>> print_items([0,1,1,1])
2
3
4
>>>
You may do it using list comprehension with enumerate() as:
>>> my_list = [0, 1, 1, 1]
>>> taken_list = [i for i, item in enumerate(my_list, 1) if item]
>>> taken_list # by default start with 0 ^
[2, 3, 4]
Alternatively, in case you do not need any in-built function and want to create your own function, you may modify your code as:
def printItems(l):
new_list = []
for x in range(len(l)):
if l[x] == 1:
new_list.append(x+1) # "x+1" because index starts with `0` and you need position
return new_list
Sample run:
>>> printItems([0, 1, 1, 1])
[2, 3, 4]
I want to change a in the for-loop to [4,5,6].
This code just print: 1, 2, 3
a = [1,2,3]
for i in a:
global a
a = [4,5,6]
print i
I want the ouput 1, 4, 5, 6.
You'll need to clarify the question because there is no explanation of how you should derive the desired output 1, 4, 5, 6 when your input is [1, 2, 3]. The following produces the desired output, but it's completely ad-hoc and makes no sense:
i = 0
a = [1, 2, 3]
while i < len(a):
print(a[i])
if a[i] == 1:
a = [4, 5, 6]
i = 0 # edit - good catch larsmans
else:
i += 1
The main point is that you can't modify the parameters of a for loop while the loop is executing. From the python documentation:
It is not safe to modify the sequence being iterated over in the loop
(this can only happen for mutable sequence types, such as lists). If
you need to modify the list you are iterating over (for example, to
duplicate selected items) you must iterate over a copy.
Edit: if based on the comments you are trying to walk URLs, you need more complicated logic to do a depth-first or breadth-first walk than just replacing one list (the top-level links) with another list (links in the first page). In your example you completely lose track of pages 2 and 3 after diving into page 1.
The issue is that the assignment
a = [4,5,6]
just changes the variable a, not the underlying object. There are various ways you could deal with this; one would be to use a while loop like
a = [1,2,3]
i = 0
while i<len(a):
print a[i]
a = [4,5,6]
i += 1
prints
1
5
6
If you print id(a) at useful points in your code you'll realise why this doesn't work.
Even something like this does not work:
a = [1,2,3]
def change_a(new_val):
a = new_val
for i in a:
change_a([4,5,6])
print i
I don't think it is possible to do what you want. Break out of the current loop and start a new one with your new value of a.