Trying to make a "folded list" in python? - python

I need to make a "folded in half list" where I multiply the first and last term, second and second to last term, third and third to last term, etc.
I know how to make a list and how to print specific values from the list, but don't understand how to do math like this within the list, without simply typing each number and multiplying them.
So far all I have is a list (called a) with six terms, and though I know how to multiply the whole times an integer, I don't know how to make this "folded" thing. Will I need to end up making a loop of some sort? If so, how?
Edit: I should have specified that I need to make it via a function. Someone helped me make one via a method that worked great, but when I realized it needed to be a function I tried it again and it won't work. See the code below.
a = [10, 14, 21, 25 ,52, 55]
print('starting list:', a)
Finding the middle of the list
len(a)//2
Using (what I think is) a function to make a new list of first + last term, etc.
Term i is the term counted from the start of the list, term -(i+1) is the term counted from the bottom of the list
print(sum((a[i]) + (a[-(i + 1) ])) for i in range( len(a) // 2)
A code that works but isn't a function since it has brackets
foldedlist=[ a[i] + a[-(i + 1) ] for i in range( len(a) // 2)]
print('folded list:', foldedlist)

Take your list, here:
l = [1, 2, 3, 4, 5, 6]
Find the mid-way point (where the fold happens - you'll need to think about how this works for an odd-numbered length list)
l_mid = len(l) / 2
Make two sublists up to, and then from the mid-point
l1 = l[:l_mid]
l2 = l[l_mid:]
Create a container for the output and then iterate over both lists, with the latter reversed and append the product to the container.
output = []
for v1, v2 in zip(l1, reversed(l2)):
output.append(v1 * v2)

As we know, indexes in list can be positive or negative. Index -1 refers to last item, index -2 refers to second last item, etc. Hence, we must have:
L[0]*L[-1]+
L[1]*L[-2]+
L[2]*L[-3]+
...+
L[mid]*L[-(mid+1)]
The general formula is: L[i]*L[-(i+1)]. So, we can use the following code:
list = [1, 2, 3, 4, 5, 6]
newList=[ list[i] * list[-(i + 1) ] for i in range( len(list) // 2)]
print(newList)
len(list) // 2 is the index of middle of list.
Output: [6, 10, 12]

Try like this:
myList = [Yourlist]
newList = []
a = myList[:len(myList)//2]
b = myList[len(myList)//2:]
b.reverse()
for x,y in zip(a,b):
newList.append(x*y)

Related

Doing math with numbers in a list

i want to be able to add, subtract, divide, multiply etc with integers in a list and in order.
I know you can use sum() to add, but i also want to be able to subtract, etc in order... so i tried making a for loop idk if thats the right thing to do, but it doesn't give me the right output and it really confuses me because it really seems like it should work. I was wondering if anyone knows how to fix this or explain why its not giving me the same output as i expected.
my_list = [100, 15, 3]
for i in my_list:
i -= i
print(i)
# 100 - 15 - 3 = 82
# Wanted output: 82
# Actual output: 0
my_list = [100, 15]
for i in my_list:
i += i
print(i)
# 100 + 15 = 115
# Wanted output: 115
# Actual output: 30
There are two main issues with your code:
i can't be your loop variable and the sum, because it will be overwritten all the time. So make two variables.
Your first task is different from the second. The sum is easy: take all the values of the list and add them, so the order is irrelevant. For your subtraction it's different because you have to take the first value and subtract all others, so it's basically +100-15-3, which means that also the order of the values in the list matter.
There are more elegant ways to solve it, but for the beginning this should be better to understand.
my_list = [100, 15, 3]
my_difference = my_list[0] #initialize with the first value of your list
my_list_sub = my_list[1:] #make a new list with the remaining numbers
for val in my_list_sub:
my_difference=my_difference-val
print(my_difference)
my_list = [100, 15]
my_sum = 0 #initialize your sum with 0
for val in my_list:
my_sum=my_sum+val
print(my_sum)
As others already pointed out: The "running"/temporary variable is overwritten in every loop. You can try this out with a simple test:
for entry in [0, 'a', 13.37]:
print(entry)
It's always a good idea of trying out what happens in simple cases to learn what is going on.
But your idea of solving this with a loop is absolutely fine. If you want to re-use this functionallity later, it is also nice to wrap that in a function.
Assume integer values my_values = [100, 50, 123, 51, 124, 121] in the following examples.
Lets first tacle the sum.
def calculate_sum(values: list) -> int:
result = 0
for entry in values:
result += entry
return result
Check that it does what we want with
print(calculate_sum(my_values))
print(sum(my_values))
Now difference is 'almost' like summing up, but you want to sum up all values but the first one, and then compute the difference to the first one (a-b-c-d = a-(b+c+d)). Great, that we have already a method for summing up stuff, so we could simply do
def calculate_difference(values: list) -> int:
first, *other = values
return first - calculate_sum(other)
Note the *-marker in front of the other variable. When assigning a list two multiple variables, they are "unpacked" by python. Thus a, b, c = [0, 1, 2] would assign 0 to a and so on. However, when we do a, b = [0, 1, 2], then python complains because there are too many variables to unpack in the list (3 > 2). With the asterisk we simply tell python to put all other values, not used so far, into this special variable again. a, b, *rest = [1, 2, 3, 4, 5, 6] is also possible.
Ok, computing the product is as easy as summing up, just replace += by *= in the method. And for the quotient we can do the same as for the difference, since a * 1/b * 1/c * 1/d = a / (b*c*d). However, note that if the divisor is zero, python will raise an Error DivisionByZero, as this is not legal. Also, the result of the method is float and no longer int.

How to append to a list two numbers from within the list that add up to a number in the list?

First, I want to find the highest number in the list which is the second number in the list, then split it in two parts. The first part contains the 2nd highest number, while the second part contains the number from the list that sums to the highest number. Then, return the list
eg: input: [4,9,6,3,2], expected output:[4,6,3,6,3,2] 6+3 sums to 9 which is the highest number in the list
Please code it without itertools.
python
def length(s):
val=max(s)
s.remove(val)
for j in s:
if j + j == val:
s.append(j)
s.append(j)
return s
Here's what I have but it doesn't return what the description states.
Any help would be appreciated as I spent DAYS on this.
Thanks,
The main issue in your code seems to be that you are editing the list s whilst iterating through it, which can cause issues with the compiler and is generally just something you want to avoid doing in programming. A solution to this could be iterating through a copy of the original list.
The second problem is that your program doesn't actually find the second biggest value in the list, just a value which doubles to give you the biggest value.
The final problem (which I unfortunately only noticed after uploading what I thought was a solution) is that the split values are appended to the end of the list rather than to the position where originally the largest value was.
Hopefully this helps:
def length(array):
val = max(array)
idx = array.index(val) # gets the position of the highest value in the array (val)
array.remove(val)
for i in array.copy(): # creates a copy of the original list which we can iterate through without causing buggy behaviour
if max(array) + i == val:
array = array[:idx] + [max(array), i] + array[idx:]
# Redefines the list by placing inside of it: all values in the list upto the previous highest values, the 2 values we got from splitting the highest value, and all values which previously went after the highest value.
return array
This will return None if there is no value which can be added to the second highest value to get the highest value in the given array.
Input:
print(length([1,2,3,4,5]))
print(length([4,8,4,3,2]))
print(length([11,17,3,2,20]))
print(length([11,17,3,2,21]))
Output:
[1, 2, 3, 4, 4, 1]
[4, 4, 4, 4, 3, 2]
[11, 17, 3, 2, 17, 3]
None
Here are the docs on list slicing (which are impossible to understand) and a handy tutorial.
when you say "The first part contains the 2nd highest number" does that mean second highest number from the list or the larger of the two numbers that add up the largest number from list?
Here I assume you just wanted the larger of the two numbers that add up to the largest number to come first.
def length(s:list):
#start by finding the largest value and it's position in the list:
largest_pos = 0
for i in range(len(s)):
if s[i] > s[largest_pos]:
largest_pos = i
# find two numbers that add up to the largest number in the s
for trail in range(len(s)):
for lead in range(trail, len(s)):
if (s[trail] + s[lead]) == s[largest_pos]:
if s[trail] > s[lead]:
s[largest_pos] = s[trail]
s.insert(largest_pos +1, s[lead])
else:
s[largest_pos] = s[lead]
s.insert(largest_pos + 1, s[trail])
return s
# if no two numbers add up to the largest number. return s
return s
Since you are limited to 2 numbers, a simple nested loop works.
def length(s):
val = max(s)
idx = s.index(val)
s.remove(val)
for i in range(len(s) - 1):
for j in range(i + 1, len(s)):
if s[i] + s[j] == val:
s = s[:idx] + [s[i], s[j]] + s[idx:]
return s
print(length([4,9,6,3,2]))
Output:
[4, 6, 3, 6, 3, 2]
I used deque library
first to find the highest element or elements then remove all of them and replace them with second high value and rest like : 9 replace with 6 and 3 in example:
from collections import deque
l = [4, 9, 6, 3, 2]
a = deque(l)
e = a.copy()
s = max(a)
while s in a:
a.remove(s) # remove all highest elements
s2 = max(a) # find second high value
c = s - s2
for i in l:
if i == s:
w = e.index(i) # find index of high values
e.remove(max(e))
e.insert(w, s2)
e.insert(w+1, c)
print(list(e))

Index out of range confusion

So i am new to programming, and i am having trouble with index out of range errors. Quick example:
I have a list, lst = (5,7,8,9,10).
I want to remove every even number, and every number to the right of an even number.
I would approach this problem by getting the index of every even number, 'i' , and removing lst[i] and lst [i+1]. That will not work when the last number is even because there is no lst [i+1] after the last element in the list.
I have run into this issue on several basic problems i have been working on. My approach to solving this is probably wrong, so i would like to know:
How can i/Can i solve the problem this way, whether it is efficient or not?
What would be the most efficient way to solve this problem?
Welcome to the club! Programming is a lot of fun and something you can always improve upon with incremental progress. I'm going to try to be exhaustive with my answer.
With lists (also known as arrays) remember that a list and its indexes are zero-based. What this means is that an array's indexes start at the number 0 (not number 1 like you would do in normal counting).
arr = [5, 7, 8, 9, 10]
# If you want to access the first element of the array
# then you would use the 0 index. If you want the Second
# element you use index 1.
print(arr[0]) # prints 5 or the 1st element
print(arr[1]) # prints 7 or the 2nd element
I would not use your stand looping technique like for or while in this case because you are removing elements are you are going for the array. If you delete the item as you are looping you are changing the length of the array.
Instead, you could create a new array from looping and only adding or appending odd values to this new array.
arr = [5, 7, 8, 9, 10]
new_arr = []
for idx, val in enumerate(arr):
if idx % 2 == 1:
new_arr.append(val)
return new_arr # yields [7,9] or this process creates a new array of odd elements
In addition, remember when you are using [i+1] while you are indexing through loop in makes sense to stop the loop an element early to avoid an out of index range error.
Do this (no error)
for idx in range(len(arr)-1):
# pseudocode
print(arr[i] + arr[i+1])
instead of this (out of index error). The reason being is that on the last element if you try to add 1 to last index and then access a value that does not exist then an error will be returned:
for idx in range(len(arr)):
# pseudocode
print(arr[i] + arr[i+1])
arr = [5, 7, 8, 9, 10]
# if you try to access arr[5]
# you will get an error because the index
# and element do not exist
# the last element of arr is arr[4] or arr[-1]
arr[5] # yields an out of index error
There are many Pythonic (almost like a colloqial phrase specific to python) ways to accomplish your goal that are more efficient below.
You can use slicing, spacing and the del (delete statment) to remove even number elements
>>> arr = [5, 7, 8, 9, 10]
>>> del arr[::2] # delete even numbers # if you wanted to delete odd numbers del arr[1::2]
>>> arr
[7, 9]
Or a list comprehension to create a new list while looping through some conditional to filter the even numbers out:
new_arr = [elem for idx, elem in enumerate(arr) if idx % 2 == 0]
The % operator is used to see if there is a remainder from division. So if idx is 10. Then 10 % 2 == 0 is true because 2 is able to divide into 10 five times and the remainder is 0. Therefore, the element is even. If you were checking for odd the condition would be:
idx % 2 == 1
You can find further explanation of these Python methods from this great Stack Overflow post here
One issue you may run into is your list indexes shifting on you during removal. One way around this is to sort the indexes to be removed in descending order and remove them first.
Here is an example of how you could accomplish what you are looking for:
myList = [5, 7, 8, 9, 10]
# use list comprehension to get indexes of even numbers into a list.
# num % 2 uses the modulus operator to find numbers divisible by 2
# with a remainder of 0.
even_number_indexes = [idx for idx, num in enumerate(myList) if num % 2 == 0]
# even_number_indexes: [2, 4]
# sort our new list descending
even_number_indexes.reverse()
# even_number_indexes: [4, 2]
# iterate over even_number_indexes and delete index and index + 1
# from myList by specifying a range [index:index + 2]
for index in even_number_indexes:
del myList[index:index + 2]
print(myList)
output: [5, 7]
You can check if i+1 is greater than (Edit: or equal to) the length of the list, and if it is, not execute the code.
You can also handle this in a try/except block.
As to the efficiency of this method of solving, seems fine to me. One gotcha in this approach is that people try to iterate over the list while modifying it, which can lead to unknown errors. If you're using the remove() function, you probably want to do it with a copy of the list.

List index out of range error while performing a binary search

I attempted to create a function that takes an ordered list of numbers and a given number, and decides whether or not the given number is inside the list. I am trying to use a binary search to accomplish this task.
I have two steps:
First, I am making list1 smaller by only taking the numbers in list1 that are smaller than the given number, and then appending those numbers into a new list, called newlist.
Next, in the while loop, I am basically taking all the numbers that are less than the number in the middle of the newlist and removing them, repeating that process multiple times until there is only one number in newlist. From there, I would compare that number to the given number. My code is shown below.
list1 = [1, 3, 5, 6, 8, 14, 17, 29, 31]
number = 7
def func(list1, number):
newlist = []
for x in list1:
if x < number:
newlist.append(x)
else:
continue
while len(newlist) > 1:
for x in range(0, len(newlist) - 1):
if newlist[x] < newlist[round(len(newlist) / 2)]:
newlist.remove(newlist[x])
else:
continue
if newlist[0] == number:
return True
else:
return False
print(func(list1, number))
I am receiving an error at line 36 (if newlist[x] < newlist[round(len(newlist) / 2)]:), that the list index is out of range. I think that the problem is that as newlist is getting smaller and smaller, the x value set by range(0, len(newlist) - 1) is staying the same?? If that is the case, I am unsure of how to remedy that. Much thanks in advance.
The issue is this bit right here:
for x in range(0, len(newlist) - 1):
if newlist[x] < newlist[round(len(newlist) / 2)]:
newlist.remove(newlist[x])
First, you're iterating over the list
[0, 1, 2, ..., len(newlist) - 1]
This list is generated when you start the loop, meaning that if len(newlist) is 7 at the beginning, the list will always go up to 6, regardless of whether things are removed from newlist, which you later do. This is what causes your error, since at some point you've removed enough elements that your list is now, say, three elements large, but python is trying to access the fifth element because the list it's iterating over isn't newlist, it's [0, 1, 2, 3, 4, 5, 6].
To fix this, you could (for example) replace the for loop with this:
x = 0
while x < len(newlist - 1):
if newlist[x] < newlist[round(len(newlist) / 2)]:
newlist.pop(x) # simple way of saying "remove item at index x"
This is essentially the way of doing a C or Java-style for loop in python, and will avoid this type of problem.
I also understand that you have an issue with the logic in your code, which was pointed out in one of the comments above and gets more to the heart of your underlying issue, but this is at least an explanation of why this error occurred in the first place, so maybe it's helpful to you in the future

Generating Padovan Sequence

The Padovan sequence is governed by the relationship P(n+1) = P(n-1) + P(n-2), for n is a
non-negative integer, where P(0) = P(1) = P(2) = 1. So, for instance, P(3) = 2, P(4) = 2, and
P (5) = 3, and so on.
I want to write a Python program Pad(n) that generates the sequence P(0), P(1), ..., P(n - 1).
This is what I have this far, but it only produces a list with the ith number replicated up to the largest number in the sequence:
def ith(n):
first, sec, third, fourth = 1, 1, 1, 1
for i in range(3, n+1):
fourth = first + sec
first = sec
sec = third
third = fourth
return fourth
def pad(n):
pad = ith(n)
lst = []
for i in range(n):
lst.append(pad)
return lst
I want it to produce this as an output:
>>> Pad(6)
>>>[1,1,1,2,2,3]
Currently my code only produces:
>>>[4,4,4,4,4,4]
I now that I append the ith value ith number of times to the list, but I dont know how to append each number in series up to and including the value for the last number. Pad(6) yields 4 since this is all the previous relationships put together.
Sorry for my bad description and formulating of the problem.
You have a two minor errors in your pad() function.
First you should be calling the ith() function inside the loop (also don't name the variable pad as that's the name of the function and it can cause problems).
Secondly, you are calling ith(n) inside the loop when you should be calling ith(i). This is the reason that you were always getting the same number- the argument to ith() was not changing inside the loop.
A fixed version of your pad() function would be:
def pad(n):
lst = []
for i in range(n):
val = ith(i)
lst.append(val)
return lst
You can verify that this indeed produces the correct output of [1, 1, 1, 2, 2, 3] for pad(6).
More efficient non-recursive method
Now, while your method works, it's also very inefficient. You are calling the ith() function for every value in range(n) which recomputes the entire sequence from the beginning each time.
A better way would be to store the intermediate results in a list, rather than by calling a function to get the ith() value.
Here is an example of a better way:
def pad2(n):
lst = [1, 1, 1] # initialize the list to the first three values in the sequence
for i in range(3,n):
lst.append(lst[i-2] + lst[i-3]) # use already computed values!
# slice the list to only return first n values (to handle case of n <= 3)
return lst[:n]
Recursive method
As seen on Wikipedia, the recurrence relation shows us that pad(n) = pad(n-2) + pad(n-3).
Use this as the starting point for a recursive function: return pad(n-2) + pad(n-3)
This is almost everything you need, except we have to define the starting values for the sequence. So just return 1 if n < 3, otherwise use the recurrence relation:
def pad_recursive(n):
if n < 3:
return 1
else:
return pad_recursive(n-2) + pad_recursive(n-3)
Then you can get the first n values in the sequence via list comprehension:
print([pad_recursive(n) for n in range(6)])
#[1, 1, 1, 2, 2, 3]
But this suffers from the same drawback as your original function as it computes the entire sequence from scratch in each iteration.

Categories

Resources