List comprehension works but not generator expression [duplicate] - python

This question already has answers here:
A safe max() function for empty lists
(7 answers)
Closed 1 year ago.
I am doing this problem:
Given an array of integers arr, a lucky integer is an integer which has a frequency in the array equal to its value.
Return a lucky integer in the array. If there are multiple lucky integers return the largest of them. If there is no lucky integer return -1.
I am using this code, which works and passed all tests:
class Solution:
def findLucky(self, arr: List[int]) -> int:
values = [n for n in arr if n if arr.count(n) == n]
return max(values) if values else -1
However, when I try to change the list comprehension to a generator expression like so:
class Solution:
def findLucky(self, arr: List[int]) -> int:
values = (n for n in arr if n if arr.count(n) == n)
return max(values) if values else -1
I get this error:
Traceback (most recent call last):
File "...", line 10, in <module>
print(Solution().findLucky([2, 3, 4]))
File "...", line 7, in findLucky
return max(values) if values else -1
ValueError: max() arg is an empty sequence
Why does a list comprehension work whereas a generator expression fails?
I've tried converting the generator expression to a list in the comprehension, but that won't work because then the generator is exhuased.

Every generator is true, so you always call max(values) even if the generator is "empty". The right way to do it is to tell max what to do then:
return max(values, default=-1)

Related

How to use Python Exception in the code given below

Q: Write a Python program to do the following:
Write a recursive Python function that has a parameter representing a
list of integers and returns the maximum number stored in the list.
Use Exception Handling to test if the list item is NOT integer and handle
it.
hint: The maximum is either the first value in the list or the maximum of the rest of
the list, whichever is larger. If the list only has 1 integer, then its maximum is
this single value, naturally.
My code:
def maxim(maximum , lst , i ):
if i == len(lst):
print(maximum)
elif maximum < lst [ i ] :
maximum = lst [ i ]
return maxim(maximum, lst , i+1 )
else :
return maxim(maximum , lst , i+1 )
lst = eval(input("Enter a list :-"))
maxim(lst[ 0 ] , lst , 1)
I've answered point 1, how can I answer point 2?
Taking it piece by piece:
Write a recursive Python function that has a parameter representing a
list of integers and returns the maximum number stored in the list.
def maximum(nums: list[int]) -> int:
If the list only has 1 integer, then its maximum is this single value,
naturally.
if len(nums) == 1:
return nums[0]
The maximum is either the first value in the list or the maximum of
the rest of the list, whichever is larger.
return max(nums[0], maximum(nums[1:]))
Use Exception Handling to test if the list item is NOT integer and
handle it.
The best place to do this is outside the function call:
try:
print(f"Maximum: {maximum([1, 2, 3, "oops"])}")
except TypeError:
print("please enter only integer")

how to write a recursive function that sums the integers in a tree?

Write a recursive function TreeSum(T) to add up all the integers in a tree. My test case is
TreeSum(set)
48
where
set=[[[[2,1],[3,7]],[1,2]],[[0,6],[[[3,2],[1,1]],[9,10]]]]
This is the code I have so far:
def TreeSum(T):
if len(T)==0:
return 0
else:
return T[0] + TreeSum(T[1:])
I am getting an error from the return line ("can only concatenate list (not "int") to list"). How can I fix this?
Error:
----> 5 return T[0] + TreeSum(T[1:])
6
7 TreeSum(maple)
TypeError: can only concatenate list (not "int") to list
#j1-lee had the correct approach, but this is limited in terms of span of the sublists (silently ignoring the items with a position > 1, or failing if one of the first two elements is an integer). You need to apply the recursive function on all sub-elements. One way is to use map
NB. I slightly changed the input to add two more elements to the first sublist
tree = [[[[2,1],1,[3,7],[1]],[1,2]],[[0,6],[[[3,2],[1,1]],[9,10]]]]
def treesum(x):
if not isinstance(x, list):
return x
return sum(map(treesum, x))
print(treesum(tree))
Output: 50

Python error "cannot unpack non-iterable int object" [duplicate]

This question already has answers here:
How to split a list into pairs in all possible ways
(14 answers)
Closed last year.
I want to get the indexes of the elements in the list which add up to the sum.
numbers = [10,2,3,5,8,200]
sum = 12
for i,v in numbers:
if i+v == sum:
print(numbers[i]), print(numbers[v])
else:
print("other")
But I get this error:
Traceback (most recent call last):
File "C:\User\User\PycharmProjects\training\tests.py", line 9, in <module>
for i,v in numere:
TypeError: cannot unpack non-iterable int object
You can't expect to get indices from a list item like this. Use enumerate() to accomplish it instead.
for i, v in enumerate(numbers):
This is the infamous Two Sum problem on LeetCode, and As LeetCode states :
We can do it in one-pass. While we are iterating and inserting elements into the hash table, we also look back to check if current element's complement already exists in the hash table. If it exists, we have found a solution and return the indices immediately.
def twoSum(nums: List[int], sum: int) -> List[int]:
hashmap = {}
for i in range(len(nums)):
complement = sum - nums[i]
if complement in hashmap:
return [i, hashmap[complement]]
hashmap[nums[i]] = i
x = twoSum(nums=numbers, sum=sum)
print(x)

'int' object is not iterable and the difference between two codes?

I want to figure the length of the shortest word in a string
Here is my code:
def find_short(s):
for x in s.split():
return min (len(x))
The correct one:
def find_short(s):
return min(len(x) for x in s.split())
so what's the difference between my code and the correct one? which piece of code is not iterable?
min() takes a sequence, and returns the smallest item in that sequence.
len() takes a sequence, and returns a single length (the length of that sequence).
Your first code calls min() on each length... which doesn't make sense, because min() expects a sequence as input.
maybe wrong but my guess is that you are returning the minimum length of x for every x...
Input: what is your question
def find_short(s):
for x in s.split(): # here s.split() generates a list [what, is, your, question]
return min(len(x)) # you will pass the length of the first element because you're only passing length of one word len(what) to min and immediately trying to return.
you need to pass iterable items to min function not int type
Where as here
def find_short(s):
return min(len(x) for x in s.split())
#here there are three nested operations:
#1. split the string into list s.split() [what, is, your, question]
#2. loop the list and find the length of each word by len(x) and put it into a tuple compression (4, 2, 4, 8)
#3. pass that tuple compression to the min function min((4, 2, 4, 8))
# and lastly return the smallest element from tuple
def find_short(s):
for x in s.split():
return min (len(x))
Here, x contains individul words. For every iteration, you will get a new word in x. len(x) returns an int. Calling min on an int will give you the error:
'int' object is not iterable
The verbose solution should be like below:
def find_short(s):
min_length = s[0]
for x in s.split():
if len(x) < min_length:
min_length = len(x)
return min_length
Now, look at the correct version.
def find_short(s):
return min(len(x) for x in s.split())
Here, this len(x) for x in s.split() part would form a generator, where each element is int(length of individual words). And, min() is called on the generator, not on individual ints. So, this works perfectly fine.
In short
>> min(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
>>
>>min([1])
>> 1

python: iteration over non sequence error

Just starting problem 164 for project euler, and i want a function to output a list of the sum of each set of 3 consecutive digits in a 20 digit number. Here is my function.
def func(n):
sumlist = []
m = str(n)
for i in range(0,18):
sumlist.append(sum(int(m[i])+int(m[i+1])+int(m[i+2])))
return sumlist
I keep getting the iteration over non sequence error and i can't figure out why i should. Any help would be appreciated, thanks.
EDIT
The full traceback is:
Traceback (most recent call last):
File "peproblem164.py", line 8, in ? print func(11201201201201201201)
File "peproblem164.py", line 5, in func
sumlist.append(sum(int(m[i])+int(m[i+1])+int(m[i+2])))
TypeError: iteration over non-sequence'
That's because
int(m[i]) + int(m[i+1]) + int(m[i+2])
isn't a sequence. It's an int. I believe you mean:
sumlist.append(sum((int(m[i]), int(m[i+1]), int(m[i+2]))
this will work because
(int(m[i]), int(m[i+1]), int(m[i+2]))
is a sequence.
All in all, it would be easier to work with a list of integers, rather than a string, so it would make sense to convert m into ints first:
m = map(int, str(n))
and then use Python's slicing syntax to get the subsequence sums:
for i in range(18): #Leaving out the start argument is equivalent to range(0, 18)
sumlist.append(sum(m[i:i+3]))
and it would be even more pythonic to use a list comprehension instead (not to mention faster):
sumlist = [m[i:i+3] for i in range(18)] #same thing as the for loop
You really don't need the sum call. Replace
sumlist.append(sum(int(m[i])+int(m[i+1])+int(m[i+2])))
with
sumlist.append(int(m[i])+int(m[i+1])+int(m[i+2]))

Categories