Where is it treated as an int? - python

I've seen answers to similar questions but I can't find the place in my code where I'm treating x as an int.
import matplotlib.pyplot as plt
import numpy as np
def aitken(x,y,value,n):
if n == 1:
return y[0]
first_array = x.pop(n-1)
second_array = x.pop(n-2)
first_y = y.pop(n-1)
second_y = y.pop(n-2)
n1 = n-1
return (aitken(first_array,first_y,value,n1)*(value - x[n-1]) - aitken(second_array, second_y,value,n1)*(value - x[n-2]))/(x[n-1] - x[n-2])
x = [1, 4, 7, 11, 15, 20, 30, 50, 77, 92, 100]
y = [5, 20, 52, 121, 228, 403, 903, 2504, 5929, 8464, 10005]
n = len(x)
x_fit = np.arange(0,104,1)
y_fit = aitken(x,y,x_fit,n)
Here's the error messages:
File "exl.py", line 17, in <module>
y_fit = aitken(x,y,x_fit,n)
File "exl.py", line 13, in aitken
return (aitken(first_array,first_y,value,n1)*(value - x[n-1]) - aitken(second_array, second_y,value,n1)*(value - x[n
-2]))/(x[n-1] - x[n-2])
File "exl.py", line 8, in aitken
first_array = x.pop(n-1)
AttributeError: 'int' object has no attribute 'pop'
Sorry if this question is too basic. I'm new to python.

Your variable first_array is an int because it's one element of your list x (which are all ints). You'd find it easier to debug if you didn't use the same names for function arguments as the variables in the main script.

Once the function reach the return value, you passed to it first_array, which you think is a list.
first_array is an integer since the pop function returns:
The last value or the given index value from the list.

The issue you are having is because you are no longer passing an array into your function when you recursively call it.
first_array = x.pop(n-1)
second_array = x.pop(n-2)
This is not giving you an array, but rather the value at location (n-1). For example:
x = [1, 4, 7, 11, 15, 20, 30, 50, 77, 92, 100]
first_array = x.pop(n-1)
# first_array = 100
# x = [1, 4, 7, 11, 15, 20, 30, 50, 77, 92]
So when you pass first_array in and try to pop x it is no longer an array and an error is being thrown. Instead you will want to modify your return so instead of passing a scalar back in you are passing an array. I hope this helps, good luck.

You can do what is expected if you use pop method whith a list:
x=[1,2,3]
f_array=x.pop(0)
print(f_array)
Output:
1
So it is not a list,so you get an error,
because you can't reapply pop on this variable, which in this case is an integer because the deleted list item is an integer

Related

Python: Parameters to Run the Same Function Multiple Times

I am studying rotating a list, and made a function to rotate the list left and right, but how can I write a code for how many times to rotate? if that makes a sense. I want to pass it as an argument to the functions.
table = [1, 10 ,20, 0, 59, 86, 32, 11, 9, 40]
def rotate_left():
(table.append(table.pop(0)))
return table
print(rotate_left())
def rotate_right():
(table.insert(0,table.pop()))
return table
print(rotate_right())
You can use for loop inside your functions and pass how many times you want to rotate as a argument.
table = [1, 10 ,20, 0, 59, 86, 32, 11, 9, 40]
def rotate_left(rotate_times):
for _ in range(rotate_times):
table.append(table.pop(0))
return table
>>> print(rotate_left(2))
>>> [20, 0, 59, 86, 32, 11, 9, 40, 1, 10]
def rotate_right(rotate_times):
for _ in range(rotate_times):
table.insert(0,table.pop())
return table
>>> print(rotate_right(2))
>>> [1, 10, 20, 0, 59, 86, 32, 11, 9, 40]
NOTE
In above scenario, be aware of the fact that, when you pass a list to a method and modify it inside that method, the changes are made in original list unless you make a deep copy, because list is a mutable type.
So, when you call rotate_left(2), it rotates the original list twice towards left. Then when you call rotate_right(2), it rotates the original list, which is already rotated by rotate_left(2), so we got the list as in initial order.
As, the functions are already modifying the original list, you can remove return table from the function (unless you want a new deep copy of list). And simply print the list after that like:
def rotate_left(rotate_times):
for _ in range(rotate_times):
table.append(table.pop(0))
>>> rotate_left(2)
>>> print(table)
>>> [20, 0, 59, 86, 32, 11, 9, 40, 1, 10]
You can write a 'for loop' and use 'range' to decide how many times you want to rotate. In this example 'rotate_left()' is called three times:
table = [1, 10 ,20, 0, 59, 86, 32, 11, 9, 40]
def rotate_left():
(table.append(table.pop(0)))
return table
def rotate_right():
(table.insert(0,table.pop()))
return table
for i in range(3):
print(rotate_left())
You can write a 'loop' and use 'range' to decide how many times you want to loop. In this example, there is a program that asks the user in which direction and how many times to turn and calculates.
def rotate_left(count,table):
for i in range (count):
(table.append(table.pop(0)))
return table
def rotate_right(count,table):
for i in range (count):
(table.insert(0,table.pop()))
return table
def main():
table = [1, 10 ,20, 0, 59, 86, 32, 11, 9, 40]
isSelect = True
while(isSelect):
rotate = int(input("1- Rotate Left\n2- Rotate Right\n: "))
count = int(input("\nHow many times to rotate ?\n: "))
if((rotate == 1 or rotate == 2) and count > 0):
isSelect = False
if (rotate == 1):
print(rotate_left(count,table))
elif (rotate == 2):
print(rotate_right(count,table))
else:
print("\nInvalid Parameter. Please choose again.\n")
main()

Selecting leftmost unique elements from multiple lists until given size is reached

I have the following lists:
a = [ 1, 6, 76, 15, 46, 55, 47, 15, 72, 58, ..] # there could be more than 10 elements in each
b = [17, 48, 22, 7, 35, 19, 91, 85, 49, 35, ..]
c = [46, 8, 53, 49, 28, 82, 30, 86, 57, 9, ..]
d = [82, 12, 24, 60, 66, 17, 13, 69, 28, 99, ..]
e = [ 1, 53, 17, 82, 21, 20, 88, 10, 82, 41, ..]
I want to write a function which takes any number of those list (could be all, could be only a and c for example) as its argument and selects the leftmost unique 10 elements equally from every list. For example, I will show in pictures with.
The initial data we have (length of 10 assumption).
We look at the first elements of every row and see a and e have same values. We randomly select let's say e, remove that element and shift it to the left and get this
Here we see that there is again overlap, 17 is appearing already and we shift e one more time
Again similar problem and we shift it one last time
Finally, we can select the first two elements of each list and there will be no duplicates
[1, 6, 17, 48, 46, 8, 82, 12, 21, 53]
It could be that more than one list could have identical values, same rules should apply.
I came with this which and for solving randomness I decided to shuffle the list before using it:
def prepare_unique_array(
arrays: list = [],
max_length: int = 10,
slice_number: int = 2
):
unique_array = []
for array in arrays:
for i in range(slice_number):
while not len(unique_array) == max_length:
if array[i] not in unique_array:
unique_array.append(array[i])
else:
while array[i+1] in unique_array:
i += 1
unique_array.append(array[i+1])
return unique_array
Which gives the desired result given those initial values, but anything changes and it does not work.
maybe there is a numpy approach which does it faster and easier as well.
I will appreciate any guide/help
Using cycle and iter to pick one element from each iterable, alternately:
from itertools import cycle
def uniques_evenly(n, *iterables):
its = cycle(iter(seq) for seq in iterables)
seen = set()
it = next(its)
for _ in range(n):
x = next(it)
while x in seen:
x = next(it) # pick next unique number
seen.add(x)
yield x
it = next(its) # switch to next iterator
Note that this will crash if one of the iterators is too short.
Testing:
a = [ 1, 6, 76, 15, 46, 55, 47, 15, 72, 58, 37756, 712, 666]
b = [17, 48, 22, 7, 35, 19, 91, 85, 49, 35, 42]
c = [46, 8, 53, 49, 28, 82, 30, 86, 57, 9]
d = [82, 12, 24, 60, 66, 17, 13, 69, 28, 99]
e = [ 1, 53, 17, 82, 21, 20, 88, 10, 82, 41, 216]
print( list(uniques_evenly(10, a,b,c,d,e)) )
# [1, 17, 46, 82, 53, 6, 48, 8, 12, 21]
Explanations
We use iter() to transform a list into an iterator. An iterator is something that "consumes" values and returns them, at every call of next(). For instance:
l = [3, 4, 7] # l is a list
i = iter(l) # i is an iterator
print( next(i) )
# 3
print( next(i) )
# 4
print( next(i) )
# 7
print( next(i) )
# raises exception StopIteration
Then, we use itertools.cycle to alternate between the five iterators. cycle returns an infinite iterator that cycles between the items in the list we gave it. We gave it a list of five iterators:
its = cycle(iter(seq) for seq in iterables)
This is the same thing as if we had written:
its = cycle([iter(a), iter(b), iter(c), iter(d), iter(e)]
Here is a demonstration with only two iterators instead of 5:
a = ['hello', 'world']
b = [5, 12]
its = cycle([iter(a), iter(b)])
it = next(its) # it is now the iterator on a
print( next(it) ) # 'hello'
it = next(its) # it is now the iterator on b
print( next(it) ) # 5
it = next(its) # it cycles back to a
print( next(it) ) # 'world'
it = next(its) # it is now b
print( next(it) ) # 12
it = next(its) # it is a
print( next(it) ) # raises exception StopIteration
So this is essentially what happens in uniques_evenly.
In addition, we use a set seen to remember the elements we have already seen. Sets are cool because testing for membership is a fast operation: if x in seen: is a constant-time operation, it doesn't matter how big seen is.
Now it is one of the five iterators, say the iterator on list d. We pick the next element in d with x = next(it); then we run the loop:
while x in seen:
x = next(it)
Which means: if x is an element already seen previously, then pick the next element in d. Keep picking the next element until you find an element that wasn't seen previously. Once we've finally picked an element x that hasn't been seen previously, we add it to set seen so it won't be picked again in the future, and then:
yield x
This is a bit special. It means uniques_evenly is not a function; if it was a function, we would have used the keyword return and not yield. Instead, uniques_evenly is a generator. Instead of using this syntax with yield, the other alternative would have been to declare a list result, initially empty, then instead of yield x, I would have written result.append(x); then at the very end of the function, return result. Then uniques_evenly would have been a function that returns a list.
The difference between a function that returns a list, and a generator, is a bit subtle. Basically a generator behaves like a lazy list, whose elements are computed and produced only when needed.
When testing my code, I immediately converted the generator to a list anyway:
print( list(uniques_evenly(10, a,b,c,d,e)) )
So the difference doesn't matter. If you're more comfortable with having a variable result and using result.append(x) instead of yield x, then returning result at the end of the function, you can do it this way instead.

Using "for" loop structure, generating numbers and filtering them by "length" and "% (mod)" structure

(Coding source)
import numpy as np
arr = np.array([2,4,9,10])
psuedo = [arr + 11 * x for x in range(1, 10)] # generate numbers using "arr" values
for i in range(len(arr)): # call each values in "arr"
if psuedo % arr[i] == 0: # each values in "arr" applies and divides to generated numbers
break # if generated numbers are divided by each "arr" values then break
else:
print(psuedo) # else, then print.
Results:
[array([13, 15, 20, 21]), array([24, 26, 31, 32]), array([35, 37, 42, 43]), array([46, 48, 53, 54])]
Expected results:
[array([13, 15, 21])], array([31]), array([35, 37, 43]), array([53])
I expected that the generated each number (results) would be divided by each of 2, 4, 9, and 10, and printed out as long it satisfied pseudo % arr[i] !=0.
What is the problem above coding?
The problem with your code is that the operation pseudo % arr[i] returns a new array of arrays with each array being replaced with the results of modding each element of that array with arr[i]. So then comparing this array of arrays to 0 doesn't make sense. What you probably want to do is iterate through all of the arrays of pseudo, and then filter out the elements from those individual arrays which don't satisfy your condition, like this:
import numpy as np
arr = np.array([2,4,9,10])
pseudo = [arr + 11 * x for x in range(1, 10)]
def is_not_mod(x):
keep = True
for mod in arr:
if x % mod == 0:
keep = False
break
return keep
for idx, array in enumerate(pseudo):
pseudo[idx] = np.array(list(filter(is_not_mod, array)))
print(pseudo)
Honestly I have almost no idea what you try to calculate. But there are some things that might fundamentally not work the way you intend.
First of all pseudo % arr[i] == 0 is wrong on multiple levels, I have no idea which Python version you are using that this does not create errors.
break stops the for-loop. My guess is that you want to use continue (go to next iteration) or pass (do nothing) instead (and thus you could simplyfiy the code omitting it completely)
This is my guess:
import numpy as np
arr = np.array([2, 4, 9, 10])
pseudo = [arr + 11 * x for x in range(1, 10)]
print([[i for i in x if (i%arr).all()] for x in pseudo])
This creates
[[13, 15, 21], [31], [35, 37, 43], [53], [57, 59, 65], [75], [79, 87], [97], [101, 103, 109]]
Let me explain:
Looping over arrays x inside pseudo and the values i in x, so the first x would be np.array([13, 15, 20, 21]) and the first i inthere would be 13.
(i%arr) is an array np.array([i%2, i%4, i%9, i%10])
.all() returns True if all values are non-zero, i.e. if your i is not divisible by any of the elements in arr.
[i for i in x if (i%arr).all()] is a list comprehension, so we create a new list with all elements in x that are not divisible by any of the elements in arr.
My output contains lists, but you can simply create np.arrays if that's better

Generating a list of evenly distributed numbers from range

I have seen this question been asked before but I'm looking for an answer with a twist:
Consider I have a range like 1-100 and i want to generate a list, with a specific stepsize like: numbers(1,100,5). This would return [1,25,50,75,100]. However, I would like it to return [1,100,50,25,75] or [1,100,50,75,25] Another example would be numbers(1,10,10) which would give me something similar to [1,10,5,2,7,3,8,4,9].
Is this even possible to do? The reason for this would be to be able to render image sequences without going from frame 1 to frame 2 to frame 3 and so forth. Instead I want to render the first frame, the last frame, the middle frame, the middle of the middle frame until all frames are accounted for.
Your question is kind of underspecified, but this should help you get started.
def numbers(first, last, count):
nums = [first, last]
width = last - first
while len(nums) < count:
width /= 2
stepper = first
while stepper < last:
rounded = round(stepper)
if rounded not in nums:
nums.append(rounded)
if len(nums) == count:
break
stepper += width
return nums
Then:
>>> numbers(0, 100, 5)
[0, 100, 50, 25, 75]
>>> numbers(0, 10, 10)
[0, 10, 5, 2, 8, 1, 4, 6, 9, 3, 7]
>>> numbers(0, 50, 50)
[0, 50, 25, 12, 38, 6, 19, 31, 44, 3, 9, 16, 22, 28, 34, 41, 47, 2, 5, 8, 11, 14, 17, 20, 23, 27, 30, 33, 36, 39, 42, 45, 48, 1, 4, 7, 10, 13, 15, 18, 21, 24, 26, 29, 32, 35, 37, 40, 43, 46]
The basic algorithm is as follows:
Start with a list of nums containing the two endpoints
Initialize width to the distance between the two endpoints
Then, loop:
Halve width
Step through first, first+width, first+2*width, ..., last-width, last, and add whichever among those are not already in nums to nums (so, for numbers(0, 100, 5), the first loop iteration will try 0, 50, and 100, and only add 50 since that wasn't already present; the second iteration will try 0, 25, 50, 75, and 100, and only add 25 and 75).
If we have enough numbers in nums, we're done
Return nums
Ok, so your desired frames are kind of wierd, especially as the elements in the first example aren't evenly ranged, eg. 100-75=25, 75-50=25, 50-25=25 , 25-1=24.
But, if we assume that you always want the start and end value in the frame and want the evenly spaced values pegged against the maximum value, we can do this:
def numbers(start,stop,step=1):
frame = [start]+range(y,stop,(start-stop)/(step-1))
return frame
The random module includes a shuffle() method that takes an array and shuffles it in-place.
Which means the function becomes:
from random import shuffle
def numbers(start,stop,step=1):
frame = [start]+range(y,stop,(start-stop)/(step-1))
shuffle(frame)
return frame
Giving us the following test runs:
>>> numbers(1,100,5)
[100, 50, 75, 1, 25]
>>> numbers(1,10,10)
[1, 3, 10, 9, 6, 5, 8, 4, 7, 2]
Original (but wrong) answer
The random module includes a shuffle() method that takes an array and shuffles it in-place.
For example:
from random import shuffle
def numbers(start,stop,step=1):
frame = range(start,stop,step)
shuffle(frame)
return frame
Then calling this function we get:
>>> numbers(1,100,25)
[1, 51, 26, 76]
>>> numbers(1,100,25)
[76, 26, 1, 51]
Note, that as per the range() function, the step value is repeatedly added to start such that the final array is of the form [start, start+1*step, start+2*step ... start + n*step], where start+n*step is less than stop while start+(n+1)*step is greater than stop.

python slicing a string of numbers in to sections based on lengths within the string

I have a string of numbers that I want to read from a file and parse into sub-sections, with lengths of the subsections based on numbers within the string. The first number in the string is the length of the first sub-section. So for example, if I have a string of data as follows:
4, 11, 22, 33, 3, 44, 55, 5, 44, 55, 66, 77
I want to divide up as follows:
first subsection is length 4, so, 4, 11, 22, 33
second subsection is length 3, so 3, 44, 55
third subsection is length 5, so 5, 44, 55, 66, 77
I tried using variables in slice, so that I could increment the start/stop values as I march through the data, but it doesn't take vars. I worked out a way to delete each subsection as I go so that the first value will always be the length of the next subsection, but it seems sort of clunky.
I'd appreciate any suggestions - thx
You can do something like:
your_list = [4, 11, 22, 33, 3, 44, 55, 5, 44, 55, 66, 77]
subsec = []
it = iter(your_list)
for n in it:
subsec.append([n] + map(lambda x: next(it), range(int(n-1))))
This way you only loop once over your list.
or
for n in it:
subsec.append([n] + [next(it) for _ in range(int(n-1))])
When dealing with more complex logic, I prefer to use regular loops.
In this case I would go with a while loop, running until the list is empty, and removing the elements already processed. If the sections are wrong (i.e. the last section goes beyond the size of the string), the assert will tell you.
sequence = [4, 11, 22, 33, 3, 44, 55, 5, 44, 55, 66, 77]
sections = []
while sequence:
section_size = sequence[0]
assert len(sequence) >= section_size
sections.append(sequence[:section_size])
sequence = sequence[section_size:]
print sections
This splits the sections and save them in a list called sections, with the size as first element, like in your examples.
Edit: added error checking.
Just thought I'd throw this out there. Very similar to both BoppreH's solution, but it avoids the overhead of creating n additional lists by iterating over indices:
def generateSlices(seq):
i = 0
while i < len(seq):
n = x[i]
yield x[i:i + n]
i += n
You can check for errors after generating a list of sublists by doing:
mySubLists = [[5, 23, 33, 44, 2], [10]]
all(len(x) == x[0] for x in mySubLists)
Incidentally, why is your data structured in this strange way? It seems error-prone.

Categories

Resources