Trouble with Basic Python exercise involving lists and indexes - python

working on CheckIO exercises but stuck here. I need to design a function that'll find the sum of the elements with even indexes (0th, 2nd, 4th...) then multiply this summed number and the final element of the array together. The input is an array, the output is a number. Oh, and for an empty array, the result has to be zero.
def checkio(array):
sum = 0
if len(array) == 0:
return 0
else:
for i in array:
if array.index(i) % 2 == 0:
sum = sum + i
final = sum*(array[len(array)-1])
return final
for instance, with the array [-37,-36,-19,-99,29,20,3,-7,-64,84,36,62,26,-76,55,-24,84,49,-65,41], this function is returning -1476 when it should be giving out 1968.

As far as I can see the issue is that you are assuming all numbers in the array are unique. For example lets say I have the following array:
[0,33,33,22,22]
obviously in this array you need the 3nd and 5th elements (index 2 and 4).
with your current code however this will never happen and you will end up with a sum of 0. This is because the code:
array.index(i)
finds the first element that matches i, this would be the 2nd and 4th elements (index 1 and 3), which are odd indexes, and thus will not be added.

You can use List Comprehension. Like:
sum([i for i in L[::2]])*L[-1]
In your code array.index(i) is problem . So you can use for finding elements by using array[::2]
You can try with your code:
def checkio(array):
sum = 0
if len(array) == 0:
return 0
else:
for i in array[::2]:
sum = sum + i
final = sum*array[-1]
return final
Example:
L = [-37,-36,-19,-99,29,20,3,-7,-64,84,36,62,26,-76,55,-24,84,49,-65,41]
Output:
1968

Here is a working program I made.
def checkio(array):
listSum = 0
if array:
for i in range(0, len(array), 2):
listSum += array[i]
finalValue = listSum * array[-1]
return finalValue
else:
return 0
First, it checks to see if the array has any values. We can do that like this: if array:. If the array is empty, it will return 0 like you wanted.
Now, this is what checks every other element in your array: range(0, len(array), 2): This means that the value of i will start at 0, continue for the length of the array, and count by twos.
The sums are added here: listSum += array[i]. This takes the variable listSum and adds the value of the number at the index i in the array to it. the += operator is shorthand for listSum = listSum + array[i].
The last part of the function, takes the listSum variable, and multiplies it by array[-1] which gets the last value in the array and finnaly returns it.
When I ran your example array above, it returned 1968 as it should.

I think it is in order to to some beginner's explanation even if I'm repeating what other answers already said:
As for why your code does not work, let's change the original a little:
def checkio(array):
sum = 0
if len(array) == 0:
return 0
else:
for i in array:
print "pos of %s = %i" % (i, array.index(i))
if array.index(i) % 2 == 0:
sum = sum + i
final = sum*(array[len(array)-1])
return final
This yields
pos of -37 = 0
pos of -36 = 1
pos of -19 = 2
pos of -99 = 3
[...]
pos of 84 = 9
[...]
pos of 84 = 9
There's your problem, because index() yields the index of the first occurrence of an element and 84 appears twice. Your code only works when the elements in the array are unique, which they are not.
So, when not going for the all out python swagger using slicing:
def checkio(array):
# sum is a built-in, don't override it
result = 0
# "if len(array) != 0" is the same as "if array"
if array:
# enumerate is nice, but not really needed, see below
for i, x in enumerate(array):
# i is the index, x is the value
if i % 2 == 0:
# += is also nice
result += x
result *= array[-1]
return result
As for a more pythonic solution, you can do a lot with slicing.
array[::2]
is every second element of array and
array[-1]
is the last element. Hence
s = sum(array[::2]) * array[-1]
That does not handle an empty array, thus
# if there are no elements or only the last element, the sum is zero
if len(array) == 0:
return 0
else:
return sum(array[::2]) * array[-1]
or even
return sum(array[::2]) * array[-1] if array else 0
Which is python's equivalent of the ternary operator.

Just use enumerate to interate for each element with an index and keep track of the last element.
def checkio(array):
sum = 0
last_element = 0
for index, element in enumerate(array):
if index % 2 == 0:
sum += element
last_element = element
return last_element * sum

Related

Don't know why the loop doesn't work (Python)

I just recently started learning Python. Tried to solve a problem where you are given an array of integers and you need to find three of them with the sum closest to target.
My idea was to sort the array and then create two pointers - one at the start of the array, moving right, and one at the end of the array, moving left. And the third pointer is supposed to move along the entire array, while the program calculates and uses the sum of all three of them. But it doesn't work. It ignores some of the indexes.
I feel like if I don't understand this I'll never understand loops in general.
nums = [0,1,1,1]
target = 100
nums.sort()
pointer_one = 0
pointer_two = len(nums) - 1
result = nums[0] + nums[1] + nums[2]
while pointer_one < pointer_two:
for i in nums:
if i == pointer_one or i == pointer_two:
pass
else:
sum_num = nums[i] + nums[pointer_one] + nums[pointer_two]
how_close = abs(target - sum_num)
if how_close < abs(target - result):
result = sum_num
pointer_one = pointer_one + 1
pointer_two = pointer_two - 1
print("Result: ", result)`
When you begin my advice is to use the print() to better understand your code:
iterate over items:
for i in nums:
print(i)
0 1 1 1
iterate over indexes:
for i in range(len(nums)):
print(i)
0 1 2 3
Regards
Your for loop iterates over the items of the list, but you use it as an index not the actual value.
The standard for loop with an index would in your case look as:
for i in range(len(nums)):
#rest of your code
Look at the docs for examples of both forms of for loops:
https://docs.python.org/3/tutorial/controlflow.html#for-statements

How to use recursion in Python to negate the last occurrence of a specific element of a list?

I need a function negate_last(n, values) that takes an integer input of n and an arbitrary list of integers values and uses recursion to negate the last occurrence of n. I have tried to code the following lines, but the function returns the list with all of the element n in the list negated. How could I fix this function in order for it to only return the last occurrence of n in the list?
def negate_last(n, values):
""" takes as inputs an integer n and an arbitrary list of integers values and that uses recursion to create and return a version of values in which only the last occurrence of n (if any) has been negated. """
if values == []:
return []
else:
rest_part = negate_last(n, values[1:])
if values[0] == n:
result = [-1 * values[0]] + rest_part
return result
else:
return [values[0]] + rest_part
'''
The below code should negate the last occurrence of n in the given array.
I think the issue in your code is that you are calling the recursive call for all non empty array which is negating all the occurrences of n. Instead if we find an occurrence (checking from right to get the last occurrence), we should treat that as a base case as we don't want to negate any more occurrences.
def negate_last(n, arr):
if not arr:
return []
if arr[-1] == n:
arr[-1] = -arr[-1]
return arr
return negate_last(n, arr[:-1]) + [arr[-1]]
print(negate_last(5, [1, 2, 5, 4, 5]))
I am not sure if this was a solution, but what I so was to add a variable for validation outside the function and once the variable change to 1, then the next time a n appears it will not change. Hope it helps
validation = 0
def negate_last(n, values):
if values == []:
return []
else:
rest_part = negate_last(n, values[1:])
if values[0] == n:
if validation == 0:
result = [-1 * values[0]] + rest_part
validation = 1
return result
else:
return [values[0]] + rest_part
else:
return [values[0]] + rest_part

How to check elements in a list WITHOUT using for loops?

Apologies if the title of the question is phrased badly. I am currently trying to make a function that takes in a list of integers from 1 to n, where n is the length of the list. The function should return the first value that is repeated in the list. Duplicates are NOT always next to one another. If one or more integers is less than 1 or if it is not a list, the function should return -1. If there are no duplicates, return 0.
This is my current code:
def find_duplicates(ls):
if type(ls) != list:
return -1
non_dupe = []
i = 0
while i < len(ls):
if ls[i] < 1:
return -1
break
if ls.count(i) > 1:
return i
break
else:
non_dupe.append(i)
i += 1
if len(non_dupe) == len(ls):
return 0
While this code works for a majority of test cases, it doesn't seem to pass
print(find_duplicates([1, 2, 2, 0]))
as it returns 2 instead of the expected -1. I am relatively new to Python and I can't seem to be able to fix this error. I've tried searching for ways to counter this problem but I am not allowed to use for loops to check through a list. Any help is greatly appreciated.
EDIT: I am not allowed to use any of the following but anything else is accepted.
for loops
min() / max()
enumerate() / zip ()
sort()
negative indexing e.g ls[-1]
list slicing
Your code returns a duplicate prematurely; traversing the list, the function first finds 2 as a duplicate, return it, and halts the function immediately. But it has not seen the 0 at the end.
So, you need to let the function see the list all the way towards the end, looking for a negative number. If a negative number is found along the way, you can halt the function. If it does not see a negative number until the end, then let it return the duplicate value:
def find_duplicates(ls):
if not isinstance(ls, list): # check whether ls is a list
return -1
dup = 0
seen = [] # list of numbers seen so far
i = 0 # index
while i < len(ls):
if ls[i] < 1: # if a negative number is found, return -1
return -1
if ls[i] in seen and dup == 0:
dup = ls[i]
seen.append(ls[i])
i += 1
return dup
print(find_duplicates([1, 2, 2, 0])) # -1
print(find_duplicates([1, 1, 2, 2, 3])) # 1
Problem is beacause you are breaking while loop when find a duplicated. In that case, function is finding first the duplicated.
Try this:
def find_duplicates(ls):
if type(ls) is not list:
return -1
duplicated = 0
i = 0
while i < len(ls):
if ls[i] < 1:
return -1
if ls.count(ls[i]) > 1 and duplicated == 0
duplicated = ls[i]
i += 1
return duplicated
Your test case returns 2 because 2 stay at lower indexes comparing to 0.
I would suggest to sort the list before moving on:
def find_duplicates(ls):
if type(ls) != list:
return -1
sorted_list = ls.sorted() #Assign sorted `ls` to another variable, while keeping the order of `ls` intact
non_dupe = []
i = 0
while i < len(ls):
if ls[i] < 1:
return -1
break
if ls.count(i) > 1:
return i
break
else:
non_dupe.append(i)
i += 1
if len(non_dupe) == len(ls):
return 0
Another method I would recommend is using set - a built-in data type of Python. Maybe you should consider trying this approach later on when all test cases are passed. Have a look at this Tutorial for set usage: https://www.w3schools.com/python/python_sets.asp.
You were very close. Try this:
def find_duplicates(ls):
if type(ls) != list:
return -1
non_dupe = []
i = 0
while i < len(ls):
if ls[i] < 1:
return -1
elif ls[i] in non_dupe:
return ls[i]
else:
non_dupe.append(i)
i += 1
return 0
my_list = [1,2,2,0]
result = list(set(filter(lambda x: my_list.count(x) > 1 , my_list)))
# Result => [2]
I hope this solves your problem

How can I count how many numbers can be fitted within particular number?

Example 1:
save([4,4,4,3,3], 12) -> 3
# 4+4+4 <= 12, but 4+4+4+3 > 12
Example 2:
save([4,4,4,3,3], 11) -> 2
# 4+4 <= 11, but 4+4+4 > 11
First of all I'm noob yet, but here is my "code" lol.
def save(sizes, hd):
sum = 0
for i in sizes:
sum = sum + i
if sum <= hd:
a = (str(sum))
print(a)
save([4,4,4,3,3], 12)
Output of this code is:
4
8
12
It would be correct if I could count length of those numbers, but I tried many ways and still couldnt found(
Thanks for helping!
You need the enumerate() function:
def save(sizes, hd):
summm = 0
for index,value in enumerate(sizes,1): # start counting at 1
summm += value
if summm <= hd:
print(summm, index) # or simply print index alone
save([4,4,4,3,3], 12)
Outputs:
12 3 # first number is the sum, second amount of numbers you added (aka 1-based index)
You can use for i in range(len(sizes)) . I think it's the fastest solution, but I'm sure it doesn't matter.
def save(sizes, hd):
sum = 0
for i in range(len(sizes)): # i values are 0,1,2,...,len(sizes)-1
sum += sizes[i] # add i-th sizes element to sum
if sum <= hd: # check if we can print answer
print(i + 1) # because i starts from 0
else: # if we can't print, we should exit cycle
break # we can use return instead
By the way, you don't need to do anything like this, because 'print()' function converts all arguments to str()
a = str(sum)
print(a)
I hope, you has learned something new!
Try this one:
def save(sizes, hd):
sum = 0
new_list = []
for i in sizes:
sum += i
new_list.append(i)
if sum >= hd:
print(new_list)
return len(new_list)
print(save([4,4,4,3,3], 12))
#print(new_list) => [4, 4, 4]
#return len(new_list) => 3
If you build a list with the cumulative sum of your sorted numbers, the position of the target value will correspond to the maximum count of numbers that will fit within your target:
from bisect import bisect_right
from itertools import accumulate
numbers = [4,4,4,3,3]
target = 12
maxCount = bisect_right(list(accumulate(sorted(numbers))),target)
print(maxCount) # 3
The bisect module provides efficient search for an index in a sorted list (bisect_right). The itertools module provides a function (accumulate) to obtain the cumulative sum of numbers in a list
I changed your code around a bit to keep it simple:
def save(sizes, hd):
size_list = [] #instead of an int, let's use a list object to hold values
for size in sizes:
size_list.append(i) # add the size to the list
if sum(size_list) <= hd: # check if sum of all values in list is <= hd
return len(size_list) # return the number of sizes inside of list
hope this helps!

Trying to systematically remove elements from a list, but some elements are left out?

I have tried to create a list of whole numbers under 1000 (aka, 0 to 999), then delete the numbers that don't comply with a certain rule [ex. must be divisible by 7 or 3]. After, I have find the sum of all these numbers. Below is the code I wrote to do so.
number_list = []
for x in range(1000):
number_list.append(x)
index = 0
element = number_list[index]
max = 1000
deleted = 0
while index < max - deleted:
element = number_list[index]
if element % 7 != 0 or element % 3 != 0:
number_list.remove(element)
deleted = deleted + 1
index = index + 1
print(sum(number_list))
This runs without any issues, but it does not return the correct sum. The correct sum is 214216, but this gives me 261832 instead, leading me to believe that more than 40 elements that should have been deleted, have not been deleted.
How can I fix this problem?
This is one way to do it using list comprehensions:
number_list = [i for i in range(1000) if not i % 7 != 0 or not i % 3 != 0 ]
print sum(number_list) #Python2
Output:
214216
Using list comprehension should be simpler for this problem. Anyway, I'll try to fix your implementation.
The condition element % 7 != 0 or element % 3 != 0 should be and
instead of or.
If a number is deleted in the loop iteration, index shouldn't move to the next, because the next element is at this index now.
In summary:
if element % 7 != 0 or element % 3 != 0:
number_list.remove(element)
deleted = deleted + 1
index = index + 1
should be:
if element % 7 != 0 and element % 3 != 0:
number_list.remove(element)
deleted = deleted + 1
else:
index = index + 1
When you remove elements from the list: number_list.remove(element), the meaning of the index changes so that on the next iteration, after incrementing index, element = number_list[index] now references a value other than the index-th item of the original number_list. Thus, some values in the original number_list are never checked.
The solution, in general, is to not mutate a list while iterating over it. Instead, use a list comprehension (or, for memory-efficiency, a generator expression) to build a new list:
In [107]: sum([i for i in range(1000) if (i % 7 == 0) or (i % 3 == 0)])
Out[107]: 214216
or, iterate over index backwards, counting from 999 down to 0, so that removing the index-th item will not affect the indexing of other items when using a smaller index.
Everything is much simpler.
sum=0
for x in range(1000):
if x % 7 == 0 or x % 3 == 0:
sum=sum+x
print sum
Result:
214216

Categories

Resources