Python code for sum with condition - python

The task is following: sum the list elements with even indexes and multiply the result by the last list's elemet.
I have this oneliner solution code in Python.
array = [-37,-36,-19,-99,29,20,3,-7,-64,84,36,62,26,-76,55,-24,84,49,-65,41]
print sum(i for i in array if array.index(i) % 2 == 0)*array[-1] if array != [] else 0
My result is -1476 ( The calculation is: 41*(-37-19+29+3-64+36+26+55+84-65) )
The right result is 1968.
I can't figure it out why this code is not working correctly in this particular case.

This is what you are looking for:
array[-1] * sum(array[::2])
array[::2] traverses the array from first index to last index in steps of two, i.e., every alternate number. sum(array[::2]) gets the sum of alternate numbers from the original list.
Using index will work as expected only when you are sure the list does not have duplicates, which is why your code fails to give the correct result.

There is a repeated element 84 in the list, thus array.index does not work as you expected it to be. Also, your code has a quadratic complexity which is not required.
To fix your code with a minimum amount of edit, it would look something like this:
array = [-37,-36,-19,-99,29,20,3,-7,-64,84,36,62,26,-76,55,-24,84,49,-65,41]
print sum(array[i] for i in range(len(array)) if i % 2 == 0)*array[-1] if array != [] else 0

>>> sum(x for i, x in enumerate(array) if not i % 2)*array[-1]
1968
Use the built-in enumerate function, since there're duplicate elements in your list, and list.index(x) returns the index of the first element equal to x (as said in the documentation). Also take a look at the documentation on enumerate.

Related

Output the index of an item in a set in Python/Sage

This is what I have so far.
def f(n):
my_list=[]
while n not in my_list:
my_list.append(n)
if n % 2 == 0:
n = n / 2
else:
n = 3 * n + 1
my_list.append(n)
return my_list
The above code takes any input n and outputs a list e.g. f(2) -> [2, 1, 4, 2]
Now I want to look at any range and output just the highest element in said list.
def f_2(i):
for i in range (1,101):
set_f = set(f(i))
print(max(set_f))
So I converted the list to a set and applied the max command to it. All of this has worked as I had intended it so far.
My problem is with the following issue:
I want to output all the indexes of all the highest Elements in all generated lists.
E.g. for i in range (1,101): The highest Element is 9232. I tried doing it in the above way, but a set does not have any indexes. However max() does not seem to work on a list of generated lists.
My try was:
def f_3(i):
for i in range (1,101):
set_f = set(f(i))
if max(set_f) == 9232:
print(set_f.index(9232))
else:
pass
Here I get the error that set has no index attribute.
def f_3(i):
for i in range (1,101):
if max(f(i)) == 9232:
print(f.index(9232))
else:
pass
Here I get the error that function has no index attribute.
Only the range of 1 to 100 is of interest to me. So I can use 9232 as a value.
Any help would be greatly appreciated, I feel a bit stuck on this one.
There's several things to unpack here, and I feel like the Code Review community would be a better fit.
First of all, why does f_2 have the parameter i? You're just using the i from the loop.
Second, why are you converting the list into a set at all? max works just fine on lists too.
set doesn't support indexing, and that's why you were getting that mistake.
At the other attempt with f_3, you've called index on the function f instead of f(i).
Function f_2 can be rewritten as such.
def f_2():
for i in range (1,101):
lst = f(i)
mx = max(lst)
print(lst.index(mx))
Function f_3 is inefficient, but it too can be fixed like this:
def f_3():
for i in range (1,101):
if max(f(i)) == 9232:
print(f(i).index(9232))

How can I avoid index out of range error with enumerating, while comparing each element to its neighbour?

I have an array that I am looping over and I want to compare each element to the element next to it, and if it is larger say, then I want to do something with its index. It's clear to me that enumeration would help in this case; however I am running into an 'index out of range error':
array = [1,2,3,4]
for index,i in enumerate(array):
if array[index]>array[index+1]:
...
While I know there are other ways of doing this,
is there a way I can make the above work with enumerate? I tried to do enumerate(array)-1 ; knowing this would not work. But anything of this sort that would fix the indexing error? Thanks
I know we can easily do the above with simply using 'i' from the for loop, but just curious if I can manipulate enumeration here.
You can just shorten the range:
for i, val in enumerate(array[:-1]):
if val > array[i+1]:
# do stuff
If you don't need the index, you can use zip to the same effect:
for prev, crnt in zip(array, array[1:]):
if prev > crnt:
# do stuff not requiring index
The slicing requires O(n) extra space, if you don't want that, you can use your original approach without enumerate, but a simple range:
for i in range(len(array)-1):
if array[i] > array[i+1]:
# ...
Use zip and slice:
for i, j in zip(array, array[1:]):
print(f'i: {i} - j: {j}')
Output:
i: 1 - j: 2
i: 2 - j: 3
i: 3 - j: 4
Doing this way will set index at 0 and i at 1. A list is starting at 0 in Python. So at i=3, you are looking at array[i+1]=array[4] which does not exist ! That is why the program is saying 'index out of range error'.
Here is what I suggest if you want to stick with lists:
array = [1,2,3,4]
for i in range(len(array)-1):
if array[i]>array[i+1]:
...
If you want to manipulate the index, then it will be the current index in your loop (i). Maybe I have not understood your issue correctly but I suggest you to use numpy if you want to work with array-like objects.
Charles
What logic do you need to apply for the last element in the list?
You can use the range function instead of enumerate.
If you don't need to implement business logic to last element, then use below:
array = [1,2,3,4]
l = len(array)
for i in range(l-1):
if array[i]>array[i+1]:
...
If you do need to implement business logic to last element then use below:
array = [1,2,3,4]
l = len(array)
for i in range(l):
if i==l-1:
implemet last elemt logic
else:
if array[i]>array[i+1]:
....

Python list first n entries in a custom base number system

I am sorry if the title is a misnomer and/or doesn't properly describe what this is all about, you are welcome to edit the title to make it clear once you understand what this is about.
The thing is very simple, but I find it hard to describe, this thing is sorta like a number system, except it is about lists of integers.
So we start with a list of integers with only zero, foreach iteration we add one to it, until a certain limit is reached, then we insert 1 at the start of the list, and set the second element to 0, then iterate over the second element until the limit is reached again, then we add 1 to the first element and set the second element 0, and when the first element reaches the limit, insert another element with value of 1 to the start of the list, and zero the two elements after it, et cetera.
And just like this, when a place reaches limit, zero the place and the places after it, increase the place before it by one, and when all available places reach limit, add 1 to the left, for example:
0
1
2
1, 0
1, 1
1, 2
2, 0
2, 1
2, 2
1, 0, 0
The limit doesn't have to be three.
This is what I currently have that does something similar to this:
array = []
for c in range(26):
for b in range(26):
for a in range(26):
array.append((c, b, a))
I don't want leading zeroes but I can remove them, but I can't figure out how to do this with a variable number of elements.
What I want is a function that takes two arguments, limit (or base) and number of tuples to be returned, and returns the first n such tuples in order.
This must be very simple, but I just can't figure it out, and Google returns completely irrelevant results, so I am asking for help here.
How can this be done? Any help will truly be appreciated!
Hmm, I was thinking about something like this, but very unfortunately I can't make it work, please help me figure out why it doesn't work and how to make it work:
array = []
numbers = [0]
for i in range(1000):
numbers[-1] += 1
while 26 in numbers:
index = numbers.index(26)
numbers[index:] = [0] * (len(numbers) - index)
if index != 0:
numbers[index - 1] += 1
else:
numbers.insert(0, 1)
array.append(numbers)
I don't quite understand it, my testing shows everything inside the loop work perfectly fine outside the loop, the results are correct, but it just simply magically will not work in a loop, I don't know the reason for this, it is very strange.
I discovered the fact that if I change the last line to print(numbers) then everything prints correctly, but if I use append only the last element will be added, how so?
from math import log
def number_to_base(n,base):
number=[]
for digit in range(int(log(n+0.500001,base)),-1,-1):
number.append(n//base**digit%base)
return number
def first_numbers_in_base(n,base):
numbers=[]
for i in range(n):
numbers.append(tuple(number_to_base(i,base)))
return numbers
#tests:
print(first_numbers_in_base(10,3))
print(number_to_base(1048,10))
print(number_to_base(int("10201122110212",3),3))
print(first_numbers_in_base(25,10))
I finally did it!
The logic is very simple, but the hard part is to figure out why it won't work in a loop, turns out I need to use .copy(), because for whatever reason, doing an in-place modification to a list directly modifies the data reside in its memory space, such behavior modifies the same memory space, and .append() method always appends the latest data in a memory space.
So here is the code:
def steps(base, num):
array = []
numbers = [0]
for i in range(num):
copy = numbers.copy()
copy[-1] += 1
while base in copy:
index = copy.index(base)
copy[index:] = [0] * (len(copy) - index)
if index != 0:
copy[index - 1] += 1
else:
copy.insert(0, 1)
array.append(copy)
numbers = copy
return array
Use it like this:
steps(26, 1000)
For the first 1000 lists in base 26.
Here is a a function, that will satisfy original requirements (returns list of tuples, first tuple represents 0) and is faster than other functions that have been posted to this thread:
def first_numbers_in_base(n,base):
if n<2:
if n:
return [(0,)]
return []
numbers=[(0,),(1,)]
base-=1
l=-1
num=[1]
for i in range(n-2):
if num[-1]==base:
num[-1]=0
for i in range(l,-1,-1):
if num[i]==base:
num[i]=0
else:
num[i]+=1
break
else:
num=[1]+num
l+=1
else:
num[-1]+=1
numbers.append(tuple(num))#replace tuple(num) with num.copy() if you want resutl to contain lists instead of tuples.
return numbers

How does % find the index which to split an array in python

So I am working on a codility training and working on the CyclicRotation where you rotate an array a given number of steps. I have found several solutions and the one that looks the best does not really make sense to me.
So the solution is:
def solution(A, K):
if not A:
return A
if K == 0:
return A
K = -K % len(A)
print(K)
print(A)
print(A[K:])
print(A[:K])
return A[K:] + A[:K]
So I get the splitting of the array by K as this will give you how many should move. But i don't get how to get K. Why do you take the -K and then % by len of the Array? That part does not make sense to me.
Imagine repeating your array infinitely in both directions. So, for example, if you have
A = [0,1,2]
imagine
[...,0,1,2,0,1,2,0,1,2,...]
Say we want to circular shift A to the right by 1. Our array A should go from [0,1,2] to [2,0,1]. The last element should become the 0'th, and every other element should advance by 1 position. In terms of solution, we want solution(A,1).
One way to think of this is that instead of starting our array at index 0 (the middle 0 value) in our infinitely-repeated array and taking the next 3 values, we can start at index -1 and take the next 3 values. Then, instead of having [0,1,2], we'd have [2,0,1]. That's what we want.
Likewise, if we want to circular shift A to the left by 1 (which would be solution(A,-1)), we can start at index 1 and count 3 values from there instead. Note that if we want to shift right, we move our index left, and vice versa.
This process is exactly what K = -K % len(A) does. The K = -K part of it deals with the fact that if you're shifting right, you can do that by moving your index to the left along the infinite sequence. The % len(A) part of it essentially treats A as an infinite sequence.

Python: divide elements of a list based on a condition

I am trying to find the LCM of first 20 natural numbers (Project Euler question 5). For that, my algorithm is:
have numbers 1 to 20 in a list
Divide only those elements of the list that are divisible by i where i is in the range (2-20).
Whatever numbers are left in the list, multiply them and that will be the lcm.
This is the naivest algorithm which we actually used to calculate lcm in school for the first time.
Now, I donot know how to divide the elements of the list based on the condition.
I have tried:
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
for x in a:
if(x%2==0):
x=x/2
This does not seem to work.
I also tried:
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
a1=[if(x%2==0): x/2 for x in a]
the above with both with and without ":" after the if condition. This does not work. I have the following questions:
a. Why isn't the first loop working correctly?
b. Can someone tell me how I can do this?
c. Will my algorithm work correctly?
a. Why isn't the first loop working correctly?
For the same reason as:
Foreach in Python not working as expected
b. Can someone tell me how I can do this?
You can do either:
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
for i, x in enumerate(a):
if x%2==0:
a[i]=x/2
Or:
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
a1=[x/2 if x%2==0 else x for x in a]
c. Will my algorithm work correctly?
I don't think so. You'll end up dividing everyone by itself and the result will always be 1.
But there are other questions here in SO that have simple answers, like:
find least common multiple of numbers 1-20
a) Why is this loop not working correctly?
As #jose-ricardo-bustos-m indicates, the x is not a reference, is a local copy to each element of the array a, and cannot modify the array in the for loop. You can use, instead:
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
for i,x in enumerate(a): #used to provide a value, and an index
if(x%2==0):
a[i]=x/2
b) Can someone tell me how I can do this?
You can try to use the ternary if operator and list comprehension:
a = [2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
b = [x/2 if x%2==0 else x for x in a]
c) Will my algorithm work correctly
You have to keep track of the numbers you have already used, and you might need to divide by the same number more than once. But if you do that, and keep dividing by the same number _until the resulting list is equal to the previous one, and then move to the next, you can later multiply all numbers used, times the remainder of the list (but if you go to the max number in the list, the remaining list will contain just 1's).
def f(l,n): # divides items in a which are divisible by n, or leaves them
return [x/n if x%n==0 else x for x in l]
lcm = 1
a=[2,3,4,5,6,7]
# we go from the smallest to the largest number in your list
for i in range(2,max(a)+1):
repeat_next_time = True
while repeat_next_time:
b = f(a,i)
if a != b:
print('Using %s as a factor' % i)
a = b
lcm *= i
# print(a) # to get the status of the a list
else:
repeat_next_time = False
# finally, for numbers which might have not been divided yet,
# multiply the lcm by all of the remaining items
lcm *= reduce(lambda x,y: x*y, a)
It works even if there are common divisors, or repeated numbers in the list. Try, for instance, with a = [2,2,2], or a = [2,3,6], or a = [8,7,4,7].
a) the variable x takes the value of the list a , but not modified, it is not a reference of list, the following code does what you want:
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
for i in range(len(a)):
if(a[i]%2==0):
a[i]=a[i]/2
b) y C)
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
def f(x):
if(x%2==0):
return x/2
return x
a1=[f(x) for x in a]
Whatever numbers are left in the list, multiply them and that will be the lcm.
reduce(lambda x, y: x*y, a1)

Categories

Resources