List with multiple conditions - python

I am creating a boolean function that checks if each element in my list is greater than 1 and less than 6. Also the list is positive integers and not negative, 0, string or anything else.
I feel like I have tried almost everything and cant find my solution. This is what I tentatively have right now.
def checkList(aList):
for i in aList:
if i < 1:
return False
elif i > 6:
return False
else:
return True

Use a generator expression to build an intermediate list of elements, then check them against all to see if they fit in your constraints.
def check_list(li):
return all((type(i) == int and 1 < i < 6 for i in li))

A single generator expression with all using isinstance(i, int) to check is each element is an int and 1 <= i <= 6 to make sure each int is in the range 1-6:
def checkList(aList):
return all(isinstance(i, int) and 1 < i < 6 for i in aList)
all will short circuit and return False for any non int or any value less than 1 or greater the 5 or return True if all the elements are ints and in the range 1-6.
In your own code you are checking for if i < 1 and elif i > 6 when you say you want to check if each element in my list is greater than 1 and less than 6 so it would be if i < 2 and elif i > 5 return False, 1 is not less than 1 and 6 is greater than 5, so to correct your own logic and to check for ints.
def checkList(aList):
for i in aList:
if not isinstance(i, int):
return False
if i < 2:
return False
if i > 5:
return False
return True # outside loop
You need to move the return True outside loop, just because one is an int
between 1 - 6 does not mean they all are.
Which could be rewritten as:
def checkList(aList):
for i in aList:
if not isinstance(i, int):
return False
if 2 > i > 5:
return False
return True

This will work for you
def check_sequence(sequence, low, high):
if all(isinstance(i, int) for i in sequence):
return all(low < i < high for i in sequence)
else:
return False
print(check_sequence([2, 5, 4, 3, 3], 1, 6))
>> True
The important concept here is low < i < high. In Python, you can specify a range of values that the variable should be between.

You could just use filter it would go something like this
filtered = filter(seq, lambda x: 1 < int(x) < 6)
That will return a filtered list containing only items which were between 1 and 6. You can then check if the list has the same length to see if anything was removed.
Going this route, your function would look like this:
def checkList(seq):
filtered = filter(seq, lambda x: 1 < int(x) < 6)
return len(filteted) == len(seq)

Related

How can I fix the output problem in my code?

So I wrote this code to print out true or false depending on whether the value goes below zero or not. Here is my code
L = [10,10,10]
init_hp = 0
def is_dead(L: list[int], init_hp:int):
if init_hp == 0:
return True
elif sum(L) + init_hp > 0:
return False
else:
return True
print(is_dead(L,init_hp))
However, for the L: list I want to make sure that the output prints out True if the value has gone below zero already. For example, if L: list = [2,-3,5], I want to make sure that the output prints out True, because 2+(-3), the first two variables, already return a negative number,"-1", EVEN THOUGH THE END RESULT IS POSITIVE... however using my code, that doesn't work, what code should I use to make sure that it will print true if a scenario like this happens
The shortest way I could think of was to use itertools.accumulate:
from typing import List
from itertools import accumulate
def is_dead(lst: List[int], i_hp: int):
if i_hp == 0:
return True
for total in accumulate(lst):
if total < 0:
return True
return False
print(is_dead([2, -3, 5], 1))
# True
print(is_dead([10, 10, 10], 1))
# False
Or slightly shorter (but also may be slightly less memory efficient):
def is_dead(lst: List[int], i_hp: int):
if i_hp == 0:
return True
if [True for total in accumulate(lst) if total < 0]:
return True
return False
Sources:
itertools.accumulate docs
You can use loop and iterate all numbers in the list.
L = [10, 10, 10]
init_hp = 0
def is_dead(L: list[int], init_hp:int):
if init_hp == 0:
return True
v = 0
for num in L:
if v+num < 0:
return True
v += num
if init_hp+v < 0:
return True
return False
print(is_dead(L,init_hp))
You can use a for loop to iterate through the numbers and check whether the sum is less than zero or not.
def is_dead(L: list[int], init_hp: int):
if init_hp <= 0:
return True
s = 0
for num in L:
s += num
if s < 0:
return True
return False # sum > 0
# Test cases:
print(is_dead([2, -3, 5], 1)) # True
print(is_dead([10, 10, 10], -1)) # True
print(is_dead([10, 10, 10], 1)) # False

Boolean True or False upon finding two consecutive digits in a given integer without using any built-in functions

To find two consecutive digits(D) in a given integer(N) without using any built-in functions and returning True or False, the following code seems to be exiting when coming across one D, however it works if there are two Ds. Why is it not working as it is and how to fix it? Thanks!
def double_digits(n, d):
"""Return True if N has two Ds in a row otherwise return False.
int, int -> Boolean
>>> double_digits(91019, 1)
False
>>> double_digits(88, 8)
True
>>> double_digits(2772, 7)
True
>>> double_digits(88108, 0)
False
>>> double_digits(12345, 4)
False
>>> double_digits(81811081, 1)
True
"""
while n > 0:
remainder = n % 10
n = n // 10
if remainder == d:
if n % 10 == d:
return True
else:
remainder, n = n % 10, n // 10
return False
The last return statement should be out of the loop.
Below is the correct code:
def double_digits(n, d):
while n > 0:
remainder = n % 10
n = n // 10
if remainder == d:
if n % 10 == d:
return True
else:
remainder, n = n % 10, n // 10
return False
You must de-indent the last statement : return False, 4 spaces to the left. That must help you.
Alternatively you can convert the input to a string and then the character matching would be easy.
def double_digits(n: int, d: int)->bool:
n = str(n)
d = str(d)
i = 0
while i < len(n)-1:
if n[i] == d and n[i+1] == d:
return True
i+=1
return False
Here I have used some builtin fuctions like len and str, but if you explicitly
want to avoid using them, just go with your original approach and just de-indent the return statement once

Project Euler #37 issue

I tried to solve Project Euler #37:
The number 3797 has an interesting property. Being prime itself, it is possible to continuously remove digits from left to right, and remain prime at each stage: 3797, 797, 97, and 7. Similarly we can work from right to left: 3797, 379, 37, and 3.
Find the sum of the only eleven primes that are both truncatable from left to right and right to left.
NOTE: 2, 3, 5, and 7 are not considered to be truncatable primes.
I wrote my code in Python but I am facing weird issues.
Here's my code:
def isPrime(n):
if n == 2 or n == 3 or n == 5: return True
if n < 2 or n%2 == 0: return False
if n < 9: return True
if n%3 == 0: return False
if n%5 == 0: return False
r = int(n**0.5)
f = 5
while f <= r:
if n%f == 0: return False
if n%(f+2) == 0: return False
f +=6
return True
def gen(nb):
results = []
nb_str = str(nb)
for k in range(0, len(nb_str) - 1):
results.append(nb_str[k:])
results.append(nb_str[-k:])
return results
def check(nb):
for t in gen(nb):
if not isPrime(int(t)):
return False
return True
c = 0
s = 0
i = 2
while c != 11:
if check(i):
c += 1
s += i
i += 1
print(s)
Where does the error come from? (The expected result is 748317)
I suspect the errors coming from the results list
Yes, the gen() function is not working correctly as your slicing is off, also, you count 2, 3, 5 and 7 as truncatable primes which the question denies.
The second slice should be the other way around:
>>> s = 'abcd'
>>> for i in range(1,len(s)-1):
... print(s[i:])
... print(s[:-i])
...
bcd
abc
cd
ab
which we can see produces the right strings.
Altogether then, the function should be:
def gen(nb):
results = [nb]
nb_str = str(nb)
for k in range(1, len(nb_str)):
results.append(int(nb_str[k:]))
results.append(int(nb_str[:-k]))
return results
note I also added a string to int conversion - not sure how Python didn't make that obvious for you :/
And before get the full solution, Project Euler nearly always gives you an example which you can use to check your code:
>>> check(3797)
True
You must also add a condition in the check function to return False if the number is 2, 3, 5 or 7 as this is stated clearly in the question.
And the result is the expected: 748317.
Joe Iddon has explained the error in your code, but you can speed it up a little by turning gen into an actual generator. That way, you can stop checking the results for a given nb as soon as you detect a composite number (and gen will stop generating them). I've also made a few minor tweaks to your primality tester. Remember, the or operator short-circuits, so if a is True-ish in a or b then it doesn't bother evaluating b.
def isPrime(n):
if n in {2, 3, 5, 7}:
return True
if n < 2 or n%2 == 0:
return False
if n%3 == 0 or n%5 == 0:
return False
r = int(n**0.5)
f = 5
while f <= r:
if n%f == 0 or n%(f+2) == 0:
return False
f += 6
return True
def gen(nb):
yield nb
nb_str = str(nb)
for k in range(1, len(nb_str)):
yield int(nb_str[k:])
yield int(nb_str[:-k])
def check(nb):
for t in gen(nb):
if not isPrime(t):
return False
return True
c = s = 0
# Don't check single digit primes
i = 11
while c < 11:
if check(i):
c += 1
s += i
print(i)
i += 2
print('sum', s)
output
23
37
53
73
313
317
373
797
3137
3797
739397
sum 748317
In fact, you can get rid of the check function, and replace it with all, which also short-circuits, like or does. So you can replace the
if check(i):
with
if all(map(isPrime, gen(i))):

lucky sevens, sum of 3 consecutive numbers in array == 7

Write a function lucky_sevens(numbers), which takes in an array of
integers and returns true if any three consecutive elements sum to 7.
Why isn't this producing an output of True? The last 3 values sum = 7.
def lucky_sevens(numbers):
x, y = 0, 3
sum_of_numbers = sum(numbers[x:y])
while (sum_of_numbers != 7) and (y < len(numbers)):
x = x + 1
y = y + 1
if sum_of_numbers == 7:
return True
else:
return False
print(lucky_sevens([1,2,3,4,5,1,1]))
The problem that when the function first gets called the sum_of_numbers variable gets assigned the value of the sum of the first 3 values in the list, and never gets updated with the new x,y values, you'd probably want to create a callback function to achieve that behavior.
As it stands, you'll need to move the sum statement into the while loop so the sum gets updated with the new x,y values:
def lucky_sevens(numbers):
result = False
x, y = 0, 3
while (y <= len(numbers)):
if sum(numbers[x:y]) == 7:
result = True
break
x += 1
y += 1
return result
print(lucky_sevens([1,2,3,4,5,1,1]))
How about something as simple as
def lucky_sevens(numbers):
for x in range(len(numbers) - 2):
if sum(numbers[x:x+3]) == 7:
return True
return False
Or with your original code, just cleaned up a little bit.
def lucky_sevens(numbers):
if len(numbers) < 3:
return False
x, y = 0, 3
sum_of_numbers = sum(numbers[x: y])
while sum_of_numbers != 7 and y < len(numbers):
x += 1
y += 1
sum_of_numbers = sum(numbers[x: y])
if sum_of_numbers == 7:
return True
return False
Your error came in your while loop. As you were looping, sum_of_numbers was staying constant. Instead, you have to update it for every new x and y within the while loop.
Also some repetitive stuff like else: return False, can be simplified to return False, as it can only get to that line if sum_of_numbers == 7 is False.
Finally x = x + 1 can be written in the more common shorthand x += 1, the same going with y = y + 1.
This ought to do the trick:
def lucky_sevens(numbers):
if len(numbers) < 3:
return False
return 7 in [sum(numbers[i:i+3]) for i in range(0, len(numbers)-2)]
print(lucky_sevens([1,2,3,4,5,1,1]))
# True
The list comprehension will move through your list 3 numbers at a time and compute the sum of each set of three integers. If 7 is in that list, then there are 3 consecutive numbers that sum to 7. Otherwise, there isn't.
The one caveat is that doing this sort of list comprehension requires that the list have more than 3 elements in it. That's why the if statement is there.
If you wanted to use your original code though, you just have to make a few adjustments. Your logic was all there, just needs a little cleaning.
def lucky_sevens(numbers):
x, y = 0, 3
sum_of_numbers = sum(numbers[x:y])
while (sum_of_numbers != 7) and (y < len(numbers)):
x = x + 1
y = y + 1
sum_of_numbers = sum(numbers[x:y])
if sum_of_numbers == 7:
return True
else:
return False
You simply needed to redo the sum within your while loop. That way, sum_of_numbers updates with each loop and each new selection of indices.
This code returns the consecutive elements in the Array whose sum is 7 and index of initial element.
function lucky_seven(arr){
let i=0;
let lastIndex = 0;
if(arr.length < 3){
return false;
}
while(i <= lastIndex){
let sum = 0;
lastIndex = i + 3;
let subArr = arr.slice(i,lastIndex);
if(subArr.length === 3) {
sum = subArr.reduce((acc, cur) => acc + cur);
if(sum === 7){
return {
subArr: subArr,
index: i
};
}
i++;
} else{
return false;
}
}
}
lucky_seven([3,2,1,4,2])
I just used this:
def lucky_sevens(numbers):
x = 0
y = False
for i in numbers:
if i == 7:
x += 7
if x == 21:
y = True
else:
x = 0
return y
There are some very interesting responses here. Thought I will share my work as well.
def lucky_seven(num_list):
if len(num_list) < 3: return False
return any([True if sum(num_list[i:i+3]) == 7 else False for i in range(len(num_list)-2)])
print ('lucky seven for [1,2,3] is :',lucky_seven([1,2,3]))
print ('lucky seven for [3,4] is :',lucky_seven([3,4]))
print ('lucky seven for [3,4,0] is :',lucky_seven([3,4,0]))
print ('lucky seven for [1,2,3,4,5,1,1] is :',lucky_seven([1,2,3,4,5,1,1]))
print ('lucky seven for [1,2,3,4,-2,5,1] is :',lucky_seven([1,2,3,4,-2,5,1]))
The output of this will be:
lucky seven for [1,2,3] is : False
lucky seven for [3,4] is : False
lucky seven for [3,4,0] is : True
lucky seven for [1,2,3,4,5,1,1] is : True
lucky seven for [1,2,3,4,-2,5,1] is : True
def f(l):
if len(l) < 3:
return False
for i in range(len(l)):
if i+3 <= len(l):
if sum(l[i:i+3]) == 7:
return True
continue
else:
return False

Palindrome with Recursion

I'm trying to make a slightly more advanced palindrome as according to the docstring. However I can't get it to work. Am I going it about the right way? This is what I have so far:
def pal_length(s: str, n: int) -> bool:
'''Return True iff s has a palindrome of length exactly n.
>>> pal_length('abclevel', 5)
True
>>> pal_length('level', 2)
False
'''
if not s:
return True
else:
index = 0
while index < len(s):
if s[index] == s[index+n]:
return pal_length(s[index+1:index+n-1],n-1)
index += 1
return False
I'm trying to not use any import modules etc. Just straight recursion.
Any help is appreciated. Thanks.
I think your indexing is a bit off. Shouldn't it be
index = 0
while index < len(s) - n + 1:
if s[index] == s[index+n-1]:
return pal_length(s[index+1:index+n-1], n-2)
index += 1
return False

Categories