Even Odd Pattern on an array where I output the sum - python

Write a function that takes an array/list of numbers and returns a number.
See the examples and try to guess the pattern:
even_odd([1,2,6,1,6,3,1,9,6]) => 393
even_odd([1,2,3]) => 5
even_odd([0,2,3]) => 3
even_odd([1,0,3]) => 3
even_odd([3,2]) => 6
def even_odd(arr):
count = 0
index = 0
length = len(arr)
while index < length:
for num in range(len(arr)):
if arr[index] % 2 != 0:
count += arr[index]
index += 1
else:
count *= arr[index]
index += 1
return count
So basically the pattern is multiply the first 2 numbers and add the third and I set it to where for each index value if it it was the first number I would add it to the count to keep track and then multiply it with the second number and then add the third. I passed 3/4 sample cases except for one which was the first one ---> even_odd([1,2,6,1,6,3,1,9,6]) => 393. I am just wondering what is the flaw with my logic and does anyone have a better way to solve this that is efficient and clean.

Your question is a challenge on Codewars (https://www.codewars.com/kata/559e708e72d342b0c900007b), so maybe you should use this platform to discuss solutions with other competitiors, instead of Stackoverflow.
The main point of this challange is to investigate the calculated pattern and not the code itself.
If you know the required pattern, the code is easy (Spoiler!):
def even_odd(arr):
num = 0
for i, e in enumerate(arr):
if (i % 2) == 0:
num += e
else:
num *= e
return num

This produces the desired results:
from operator import add, mul
def even_odd(nums):
acc = nums[0] # accumulator
ops = [mul, add]
i = 0
for num in nums[1:]:
acc = ops[i](acc, num)
i = 1 - i # alternates between the two operators
return acc

Related

traversing through a list using recursion

So I am new to recursion and I am trying to make a program where you can enter a list and python tests each integer (lets say 9 for example) and sees if the integer following it is doubled. So if I entered a list of 2 4 8 16 32, would return 4, and -5 -10 0 6 12 9 36, would return 2 because -5 followed by -10 is one and 6 followed by 12 is the second. This is the code I have so far. I feel like I am very close. but just a few thing stand in my way. Any help would be great!
L = []
def countDouble(L):
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
print(y[1])
print(y[0])
count = 0
y[0] += y[0]
# unsure of how to multiple y[0] by 2
if y[0]*2 == y[1]:
count += 1
else:
count += 0
#how would I traverse through the rest of the entered list using recursion?
print(count)
countDouble(L)
If you want/need to solve it using recursion, the following will do the trick:
def count_sequential_doubles(li, count=0):
return count_sequential_doubles(li[1:], count + int(li[0] * 2 == li[1])) if len(li) > 1 else count
I would suggest this recursive way:
def countDouble(L):
count = 0
if len(L) == 1:
return count
else:
if int(L[0])*2 == int(L[1]):
count += 1
return count + countDouble(L[1:])
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
count = countDouble(y)
print(count)
I urge you to read the entire answer, but in case you are not interested in tips, notes and the process of finding the solution, here are two solutions:
solution using recursion (not recommended):
x = input()
y = x.split(' ')
count = 0
def countDouble(i):
if(i+1 == len(y)):
return 'recursion ends here when'
if(int(y[i])*2==int(y[i+1])):
count += 1
countDouble(i+1)
countDouble(0)
print(count)
this solution just imitates a while loop:
solution using a while loop (recommended):
x = input()
y = x.split(' ')
count = 0
i = 0
while(i < len(y) - 1):
if(int(y[i]) * 2 == int(y[i+1])):
count += 1
i += 1
print(count)
Before I continue, here are a few tips and notes: (some of them will only make sense after)
I assume the 14 in your example is a typo
I didn't put the code in a function because it's not needed, but you can change it easily.
In your code, you are passing L as a parameter to the countDouble() function, but you don't use it. if you don't need a parameter don't pass it.
when splitting the input, the values of the list are still strings. so you have to invert them to integers (for instance, you can do that with the int() 'function') before comparing their values - otherwise multiplying by 2 will just repeat the string. for example: '13'*2 is the string '1313'
I don't know why you why you added y[0] to itself in line 9, but based on the code that comes after this would yield incorrect results, you don't need to change the elements in order to get their value multiplied by 2.
notice that in the else block, nothing has changed. adding 0 to the count doesn't change it. so you can remove the else block entirely
While it's possible to solve the problem in recursion, there's something else designed for these kind of problems: loops.
The problem is essentially repeating a simple check for every element of a list.
This is how I would arrive to a solution
so we want to run the following 'code':
if(y[0]*2 == y[1]):
count += 1
if(y[1]*2 == y[2]):
count += 1
if(y[2]*2 == y[3]):
count += 1
...
of course the computer doesn't understand what "..." means, but it gives us an idea to the pattern in the code. now we can do the following:
divide the extended 'code' into similar sections.
identify the variables in the pattern - the values that change between sections
find the starting values of all variables
find a pattern in the changes of each variable
find a breaking point, a condition on one of the variables that tells us we have reached the last repeating section.
here are the steps in this specific problem:
the sections are the if statements
the variables are the indexes of the elements in y we compare
the first index starts at 0 and the second at 1
both indexes increase by one after each if-statement
when the second index is bigger then the last index of y then we already checked all the elements and we can stop
so all is left is to set the needed variables, have a while loop with the breaking condition we found, and in the while loop have the general case of the repeating sections and then the changing of the variables.
so:
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
count = 0
# setting the starting values of the variables
index1 = 0
index2 = 1
# creating a loop with the breaking condition
while(index2 < len(y)):
# the general case of the repeated code:
if(int(y[index1]) * 2 == int(y[index2])):
count += 1
# changing the variables for the next loop
index1 += 1
index2 += 1
print(count)
We see that the index2 is just index1 + 1 at all time. so we can replace it like that:
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
count = 0
index1 = 0
while(index1 + 1 < len(y)):
if(int(y[index1]) * 2 == int(y[index1 + 1])):
count += 1
index1 += 1
print(count)
Note: You can use a for loop similarly to the while loop
So in summary, you can use recursion to solve the problem, but the recursion would just be imitating the process of a loop:
in each call, the breaking condition will be checked, the repeated code would run and the variables/parameters would change.
Hope you find this answer useful :)
Final edit: OP edited his example so my other code didnt apply
Some good questions people are asking, but in the spirit of helping, here's a recursive function that returns the count of all doubles.
def get_doubles_count_with_recursion(a_list, count, previous=None):
while a_list:
try:
first = previous if previous else a_list.pop(0)
next_item = a_list.pop(0)
except IndexError:
return count
if next_item / 2 == first:
count += 1
return get_doubles_count_with_recursion(a_list, count, next_item)
return count
a_list = [1, 3, 5, 10, 11, 14, 28, 56, 88, 116, 232, 464, 500]
doubles = get_doubles_count_with_recursion(a_list, 0)
print(doubles == 5)
Probably could clean it up a bit, but it's a lot easier to read than the other guy's ;)
If I'm reading your question right, you want a count of all pairs where the 2nd item is double the first. (and the 14 in the first list is a typo). In which case a simple function like this should do the job:
#a = [2,4,8,16,32]
a = [-5, -10, 0, 16, 32]
count = 0
for i, x in enumerate(a):
# Stop before the list overflows
if i < len(a) - 1:
# If the next element is double the current one, increment the counter
if a[i+1] == x * 2:
count = count + 1
else:
break
print(count)

Finding number of positive numbers in list

I'm trying to find the number of positive numbers in the list using python and I want the code to run in O(log(n))
the list is of type Positive-Negative if there's a negative number it will be on the right-hand side of the list and all the positives are on the left side.
for example, if the input is :
lst=[2,6,0,1,-3,-19]
the output is
4
I've tried some methods but I didn't get the result that I wanted
this is the last form that I get until now:
def pos_neg(lst):
if int(len(lst)) is 0 or (int(len(lst)) is 1 and lst[0] <0):
return 0
elif len(lst) is 1 and lst[0] >=0:
return 1
leng = (int(len(lst))) // 2
counter = 0
index = 0
while(leng != 0):
if lst[leng] >=0 and lst[leng+1] <0:
index = leng
break
if lst[leng] >=0 and lst[leng + 1] >=0:
if int(len(lst)) < leng + int(len(lst)):
return 0
else:
leng = (leng + int(len(lst))) // 2
if lst[leng] <0 and lst[leng + 1] <0:
leng = leng // 2
return index
You can use recursion. Every time the list is halved, so the complexity is O(logn)
def find_pos(start, end, l, count):
if(start > end):
return count
middle = start + (end-start)//2
if(l[middle] >= 0): # that means all left side is positive
count += (middle-start) + 1
return find_pos(middle+1, end, l, count)
else: # that means I am in wrong region
return find_pos(start, middle-1, l, count)
lst=[2,6,0,1,-3,-19]
find_pos(0, len(lst)-1, lst, 0)
>>> 4
Update:
If you want one function passing only lst
def find_positives(l):
return find_pos(0, len(l)-1, l, 0)
find_positives(lst)
What you describe is a bisection algorithm. The standard library provides value search bisection for ascending sequences, but it can be easily adjusted to search for positive/negative in sign-descending sequences:
def bisect_pos(nms):
"""
Do a right-bisect for positive numbers
:prams nms: numbers where positive numbers are left-aligned
This returns the index *after* the right-most positive number.
This is equivalent to the count of positive numbers.
"""
if not nms:
return 0
# the leftmost/rightmost search index
low_idx, high_idx = 0, len(nms)
while low_idx < high_idx:
mid_idx = (low_idx + high_idx) // 2
if nms[mid_idx] < 0: # negative numbers – search to the left
high_idx = mid_idx
else: # positive numbers – search to the right
low_idx = mid_idx+1
return low_idx
I usually find binary searches that repeatedly compute the middle difficult to confirm as correct, whereas constructing the index we're looking for bit-by-bit is always clear to me. So:
def find_first_negative(l):
if not l or l[0] < 0: return 0
idx = 0 # Last positive index.
pot = 1 << len(l).bit_length()
while pot:
if idx + pot < len(l) and l[idx + pot] >= 0:
idx += pot
pot >>= 1
return idx + 1
Idea of algorithm is following:
you assign two variables: left = 0 and right=len(lst)-1
then cycle calculating middle index as middle = (left + right) // 2
and check sign of lst[middle]. Then assign left = middle or right = middle depending on this check. Then cycle repeats while left < right and not equal.
As result your middle element will point to last positive or first negative depending on how you make comparison.

Find out how many zeros a number has at the end (string index out of range error when number is 0)

I am trying to solve the problem in the title, and I'm getting an IndexError.
def count_zeros(number:int) -> int:
number = str(number)
i = 0
j = -1
while number[j] == '0'
i += 1
j += -1
return i
This code spits out the IndexError only when the number is 0. I cannot figure out why.
>>>count_zeros(0)
IndexError Traceback (most recent call last)
<ipython-input-45-688099e7700c> in <module>
----> 1 end_zeros(0)
<ipython-input-43-181de92af60c> in end_zeros(number)
4 i = 0
5
----> 6 while number[j] == '0':
7 i += 1
8 j -= 1
IndexError: string index out of range
I would use the modulus here and count the number of zeroes on the right:
def count_zeros(number:int) -> int:
if number == 0:
return 1
else:
count = 0
while True:
if number % 10 != 0 or number == 0:
break
count = count + 1
number = number / 10
return count
This approach is straightforward, and will almost certainly outperform casting the input integer to a string and then checking for trailing zeroes.
As an alternative approach to iteration, using regular expressions proves to be a simple approach.
Since your code converts the number to a string already, it doesn't hurt to pass the string directly to re.search to find the trailing zeros for you effortlessly.
Here is a working example, along with some test cases:
import re
def count_zeros(number: int) -> int:
count = re.search(r'0+$', str(number))
return len(count[0]) if count else 0
print(count_zeros(1))
print(count_zeros(123))
print(count_zeros(0))
print(count_zeros(10))
print(count_zeros(12300))
print(count_zeros(123000))
Output:
0
0
1
1
2
3
How many zeros does a number have at the end
def count_zeros(num: int) -> int:
return len(str(num)) - len(str(num).rstrip('0'))
print(count_zeros(0)) #1
print(count_zeros(1)) #0
print(count_zeros(10)) #1
print(count_zeros(245)) #0
print(count_zeros(101)) #0
print(count_zeros(100100)) #2
For this problem, honestly, the simplest solution is likely going to be to handle the case where number==0 separately, by putting something like this at the top.
if number ==0:
return 1
Your loop with an iterator and a count works, but I would prefer to cast to a list so I don't have to keep track of two variables...assuming performance is not a huge concern here.
So something like:
def count_zeros(number:int) -> int:
if number==0:
return 1
number_list = list(str(number))
is_zero = True
zero_count = 0
while is_zero:
if int(number_list.pop())==0:
zero_count += 1
else:
is_zero = False
return zero_count
def end_zeros(a: int) -> int:
count = 0
list = [int(x) for x in str(a)]
list.reverse()
list.append(1)
for x in list:
if x == 0:
count += 1
else:
return count

Invalid syntax Sum += 1

It says I have invalid syntax at Sum += 1. If my code is incorrect what is a better way to go about counting how many even numbers are in a list?
def countEvens(listOfInts):
'''
- Returns an integer value representing the number of even numbers that
exist in listOfInts.
- Return 0 if listOfInts is not a list type or if no even number exists
in listOfInts.
- Note: elements in listOfInts can contain any data type.
'''
Sum = 0
for x in listOfInts:
if x % 2 == 0:
return Sum += 1
if type(listOfInts) != list:
return 0
In Python you cannot return assignments. And Sum += 1 is an assignment, it assigns Sum + 1 to Sum.
In fact the return isn't just a SyntaxError it's also wrong (in a logical sense), so just remove it:
Sum = 0
for x in listOfInts:
if x % 2 == 0:
Sum += 1
return Sum
Alternatively you can use sum with a generator:
return sum(1 for value in listOfInts if value % 2 == 0)
The syntax error comes from this line, as you say
return Sum += 1
That's because (Sum += 1) is not a valid value to return from a function. It's a separate statement
Keeping your code as close as possible, try this
Sum += 1
return Sum
or, more simply
return Sum+1
As for a more pythonic approach
def countEvens(listOfInts):
return sum( x % 2 == 0 for x in listOfInts )
does the entire thing

Python: while loop inside else

def is_prime(x):
count = 1
my_list = []
while count > 0 and count < x:
if x % count == 0:
my_list.append(x/count)
count += 1
return my_list
my_list = is_prime(18)
def prime(x):
my_list2 = []
for number in my_list:
if number <= 2:
my_list2.append(number)
else:
count = 2
while count < number:
if number % count == 0:
break
else:
my_list2.append(number)
count += 1
return my_list2
print prime(18)
Just started out with Python. I have a very simple question.
This prints: [9, 3, 2].
Can someone please tell me why the loop inside my else stops at count = 2? In other words, the loop inside my loop doesn't seem to loop. If I can get my loop to work, hopefully this should print [2, 3]. Any insight is appreciated!
Assuming that my_list2 (not a very nice name for a list) is supposed to contain only the primes from my_list, you need to change your logic a little bit. At the moment, 9 is being added to the list because 9 % 2 != 0. Then 9 % 3 is tested and the loop breaks but 9 has already been added to the list.
You need to ensure that each number has no factors before adding it to the list.
There are much neater ways to do this but they involve things that you may potentially find confusing if you're new to python. This way is pretty close to your original attempt. Note that I've changed your variable names! I have also made use of the x that you are passing to get_prime_factors (in your question you were passing it to the function but not using it). Instead of using the global my_list I have called the function get_factors from within get_prime_factors. Alternatively you could pass in a list - I have shown the changes this would require in comments.
def get_factors(x):
count = 1
my_list = []
while count > 0 and count < x:
if x % count == 0:
my_list.append(x/count)
count += 1
return my_list
# Passing in the number # Passing in a list instead
def get_prime_factors(x): # get_prime_factors(factors):
prime_factors = []
for number in get_factors(x): # for number in factors:
if number <= 2:
prime_factors.append(number)
else:
count = 2
prime = True
while count < number:
if number % count == 0:
prime = False
count += 1
if prime:
prime_factors.append(number)
return prime_factors
print get_prime_factors(18)
output:
[3, 2]
Just to give you a taste of some of the more advanced ways you could go about doing this, get_prime_factors could be reduced to something like this:
def get_prime_factors(x):
prime_factors = []
for n in get_factors(x):
if n <= 2 or all(n % count != 0 for count in xrange(2, n)):
prime_factors.append(n)
return prime_factors
all is a built-in function which would be very useful here. It returns true if everything it iterates through is true. xrange (range on python 3) allows you to iterate through a list of values without manually specifying a counter. You could go further than this too:
def get_prime_factors(x):
return [n for n in get_factors(x) if n <= 2 or all(n % c != 0 for c in xrange(2, n))]

Categories