def nested_count(l : 'any nested list of int', a : int) -> int:
c = 0
while len(l) != 0:
for x in l:
if type(x) == int:
if x == a:
c = c + 1
l.remove(x)
nested_count(l,a)
else:
continue
elif type(x) == list:
nested_count(x,a)
return c
this function passed a nested list of ints and a single int as arguments; it returns the number of times the single int argument appears in the nested list argument, for example:
nested_count( [[1,2,[4,[1],8],[1,3,2]],[1,1]], 1 )
returns 5
I am not sure why my function does not work
can someone tell me how to fix it? many thanks.
You are not adding nested_count results to c:
def nested_count(lst, l):
c = 0
for i in lst:
if i == l:
c += 1
elif type(i) == list:
c += nested_count(i, l)
return c
Also it is better to iterate over list with for.
The results of the nested function calls are not used. You probably should replace the lines with c += nested_count(l,a) and c += nested_count(x,a), respectively.
You shouldn't mutate the list while iterate over it and you need to return the result from recursive calls. You could simplify function greatly by checking the type of l and if it's int then returning bool telling if it matches with a. In case l is a list just call nested_count recursively on its' items and sum the result:
def nested_count(l, a):
# Base case
if type(l) == int:
return l == a
return sum(nested_count(x, a) for x in l)
As others have mentioned you need to accumulate the return values from the recursive calls of nested_count to get the correct total.
Also, removing items from a list (or other collection) that you're iterating over can lead to unexpected results, see the SO Python Common Question Removing items from a list while iterating over the list for details and a few relevant SO pages, in particular: Removing from a list while iterating over it.
It's generally preferred to call isinstance rather than type to do type testing. The isinstance function can test for multiple types in one call, it will also return True if the object is a subclass of the specified type.
Here are a couple of one-liners that handle lists or tuples.
def nested_count(l, a):
return sum(nested_count(x, a) if isinstance(x, (list, tuple)) else x == a for x in l)
and
def nested_count(l, a):
return l.count(a) + sum(nested_count(x, a) for x in l if isinstance(x, (list, tuple)))
Why the heterogenous list? Why bother using typing if you're not going to type all the parameters? Why are you mutating the input?
from typing import List
def deep_count_elem (x:int, xs:List) -> int:
# done
if len(xs) == 0:
return 0
# if list, count in this list and recurse
elif isinstance(xs[0], list):
return deep_count_elem(x, xs[0]) + deep_count_elem(x, xs[1:])
# if element matches, add 1
elif x == xs[0]:
return 1 + deep_count_elem(x, xs[1:])
# otherwise add nothing, move to next element
else:
return deep_count_elem(x, xs[1:])
print(deep_count_elem(1, [[1,2,[4,[1],8],[1,3,2]],[1,1]])) # 5
Related
This question already has answers here:
What's the canonical way to check for type in Python?
(15 answers)
Why does "a == x or y or z" always evaluate to True? How can I compare "a" to all of those?
(8 answers)
Closed 6 months ago.
I have two problems that are getting errors that I would like to understand. They are likely for similar reasons, hence why I'm grouping them together in this post. I am here to learn how I can understand solving errors like these!
First, one function aims to find even numbers within a list that contains ints, floats, and strings. For some reason, I get an error that says not all of my arguments were able to convert during string formatting.
Here is my code:
def recEvenNumbers(lst):
'return a count of all the even numbers(ints and floats) in the list'
evens = 0
if lst == []:
return
else:
if type(lst[0])== int or float:
if ((lst[0]%2*10))==0:
evens = evens+1
return recEvenNumbers(lst[1:], evens + 1)
I believe I have this whole function down except this one error. Why is this happening and how can I prevent this in the future?
Another error I am getting is for a different function. Here is the code for that one:
def recMerge(a,b):
'Merge two strings together recursivly'
if len(a)==0:
return
elif len(b)==0:
return
else:
if type(a) == str:
if type(b) == str:
return a[0] + b[0] + recMerge(a[1:], b[1:])
The aim of this function is to merge two strings to create one string that has characters that alternate between each of the two strings. Not really important to my question though, I just want to know why I might be getting a TypeError here. This is what it tells me:
File "C:/Users/1734/py.py", line 59, in recMerge
return a[0] + b[0] + recMerge(a[1:], b[1:])
TypeError: can only concatenate str (not "NoneType") to str
>>>
Why is this happening? I assumed my if type(a) and if type(b) were supposed to handle this. Why can't I use those in this scenario? Or am I just misusing them?
Also, are these two errors related? I know that question may seem strange but if there's a certain element of these questions that I am struggling to understand, I would like to pinpoint what it is and why I am misunderstanding it.
Thanks for your time!
You've committed one of the classic blunders. This statement does not do what you think it does:
if type(lst[0])== int or float:
This is parsed by Python as:
if (type(lst[0])== int) or (float):
And since "float" is always true, you will always take the if here. And when lst[0] is a string, the '%' operator is the string formatting operator. You want:
if type(lst[0]) in (int, float):
or even
if isinstance(lst[0],int) or isinstance(lst[0],float):
The problem with your second function is that it returns None rather than an empty string for the base case where the input is empty. Since your recursion works by adding onto the result of the recursive call, the very last recursive call must be something you can add to.
def recMerge(a: str, b: str) -> str:
"""Merge two strings together recursively. If the strings are of
unequal length, the remainder of the longer string is dropped."""
# Type check (not necessary if you type-annotate and mypy your code!)
if not isinstance(a, str) or not isinstance(b, str):
raise TypeError("both parameters must be strings!")
# Base case: if one param is empty, there's nothing to merge, so return ""
if not a or not b:
return ""
# Recurse with a smaller slice of both parameters.
return a[0] + b[0] + recMerge(a[1:], b[1:])
For the first recursive function, this is the correct code
def recEvenNumbers(lst, evens):
if not lst:
return evens
if type(lst[0]) == int:
if(lst[0]%2 == 0):
return recEvenNumbers(lst[1:], evens + 1)
else:
return recEvenNumbers(lst[1:], evens)
else:
return recEvenNumbers(lst[1:], evens)
x = recEvenNumbers([1, 2, 3, 4, 5.3, 7, 8, "h", 46, "32"], 0)
print(x)
It is important to return when you're writing a recursive function, otherwise, you get "None". When you're calling to a function make sure to add every parameter ex:(last, evens).
I know everyone else is commenting your first problem, but it works if you work it right. That said, you should handle the string first and add evens as a None parameter to check on instance for the first pass.
Here's a working function:
def recEvenNumbers(lst, evens = None):
'return a count of all the even numbers(ints and floats) in the list'
if evens is None:
evens = [0]
if lst:
# To keep things organized, extract first item
# into variable and the rest into a smaller list with
# star selection
item, *lst = lst
# Check for string first
# Pass rest of process if detected.
if type(item) == str:
pass
# Continue as you were before
elif type(item) == int or float:
if item % 2 * 10 == 0:
evens[0] += 1
# Recurse with appropriate params.
return recEvenNumbers(lst, evens)
# Return result.
return evens[0]
Run the function:
test_list = [1, 2.2, 4, "string"]
recEvenNumbers(test_list)
Output:
1
Part 2:
# Function with commentary.
def recMerge(a, b):
'Merge two strings together recursivly'
# Check types
if type(a) == type(b) == str:
# Run until b is empty.
if len(b) > 0:
# Deconstructing into single and rest of items with asterisk.
aa, *a_rest = a
bb, *b_rest = b
# New `a` value that prepends the rest of a in
# front of the concatenation of the current a and b characters.
# Since a_rest is a list, we should "collect" the items back into
# a proper string format.
a = "".join(a_rest) + aa + bb
# Return the new a with another concatenated list for the
# remaining b items.
return recMerge(a, "".join(b_rest))
# Return a. Ensure that it is a string.
return "".join(a)
Run test case:
A = "abc"
B = "def"
recMerge(A, B)
Output:
'adbecf'
here is my working code.
def recEvenNumbers(lst):
'return a count of all the even numbers(ints and floats) in the list'
evens = 0
if lst == []:
return 0
elif type(lst[0]) == int or type(lst[0]) == float:
if ((lst[0]%2))==0:
evens = evens+1
return recEvenNumbers(lst[1:]) + evens
def recMerge(a,b):
'Merge two strings together recursivly'
if type(a) != str or type(b) != str:
return None
#recMerge ((a[1:]), (b[1:]))
if a == "":
return b
elif b == "":
return a
else:
return a[0] + b[0] + recMerge(a[1:], b[1:])
I have a nested list and I want to return the number of nested list (or the depth) and the element value if the depth reaches 0. For example, with below nested list, the value I want to return is (13, 37). But my code returns 36 only.
nested = [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[13]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
def search(a, depth=0):
count = 0
for e in a:
if isinstance(e, list):
count = count + 1 + search(e)
return count
search(nested)
How should correct my code to make it return (13, 37) as expected?
This gives the right answer for a single value wrapped in a single set of lists. Not sure why you are iterating over the elements of the list. Are there potentially multiple nested sub lists/values?
nested = [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[13]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
def search(a, depth=0):
if type(a) is list:
return search(a[0], depth + 1)
else:
return a, depth
print(search(nested))
You're not counting the outermost list. To correct this, pull the list check outside of the loop. To return the inner value, retrieve it when the list element is not a list anymore:
def search(a):
count = 0
if isinstance(a, list):
count += 1
for e in a:
inner_value, count_inc = search(e)
count += count_inc
else:
inner_value = a
return inner_value, count
A good recursive function has a base case and a recursive case. Ruswick's (good) answer can be modified to meet these criteria:
def search(a, depth=0):
if type(a) is int: #base case
return a, depth
return search(a[0], depth + 1) #recusive case
print(search(nested))
#(13, 37)
You can use a recursive generator function to handle inputs with more than one non-list element:
def search(d, c = 0):
for i in d:
if not isinstance(i, list):
yield (i, c)
else:
yield from search(i, c+1)
nested = [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[13]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
print(list(search(nested)))
Output:
[(13, 36)]
Okay. I feel a bit silly for having so much trouble with this problem, but essentially, here's the code I have so far:
def addition_nest(x):
netsum = 0
sublist = []
if isinstance(x, int):
return x
if isinstance(x, list):
for sublist in x:
if sublist == []:
return netsum
else:
netsum = netsum + addition_nest(sublist)
return netsum
I keep getting an error saying the operand + does not work with int and NoneTypes. Any ideas on how I can bypass this? The code basically needs to be able to add up all the integers in a list/nested list, and omit any other elements within the list.
This code will get you the expected output.
def addition_nest(x):
netsum = 0
if isinstance(x, int):
# if isinstance(x, (int, float)):
return x
elif isinstance(x, list):
for each_element in x:
if isinstance(each_element, int):
# if isinstance(each_element, (int, float)):
netsum += each_element
elif isinstance(each_element, list):
netsum += addition_nest(each_element)
return netsum
print(addition_nest(25)) ## Output: 25
print(addition_nest([25, 30, 'a'])) ## Output: 55
print(addition_nest([25, 30, ['a', 10, 20]])) ## Output: 85
If you want the above code to work with float also, replace the if conditions with the commented lines.
In your existing code, you have handled the scenarios for when an element inside the parent list is another list or an integer. But you didn't handle it for other data types. That is the reason for the error you are facing.
First of all, the third line is not used and pointless
sublist = []
Second, in cases that it is a list just simply call the function on every element and add together.
def addition_nest(x):
netsum = 0
sublist = []
if isinstance(x, int):
return x
if isinstance(x, list):
for sublist in x:
netsum = netsum + addition_nest(sublist)
return netsum
This will do.
I think the problem is simpler than you and other answers are making it. First rule of recursion is let the recursion do the work:
def addition_nest(unknown):
if isinstance(unknown, list):
if unknown: # not empty
head, *tail = unknown
return addition_nest(head) + addition_nest(tail)
return 0 # empty
if isinstance(unknown, (int, float)):
return unknown
return 0 # neither list nor number
OTOH, if we want to reduce recursion and increase efficiency, we could move in the direction of something like:
def addition_nest(unknown):
if isinstance(unknown, (int, float)):
return unknown
if isinstance(unknown, list):
return sum(map(addition_nest, unknown))
return 0
Which is still recursion, though indirectly as we don't directly call the function from itself but rather hand it off to map().
Is it possible to return tuples of only even indexes through recursion?
This is what I came up with it so far.
def even(tup):
if not tup:
return ()
if tup.index(tup[0])+1 % 2 == 0:
return tuple(tup[0]) + even(tup[1:])
Passed argument gonna be look like this:
('c','b','z','e','m','f','j')
And my desired result would be:
First element in the tuple count as 1 = 'c', so for the even numbers it would return b, e, and f instead.
('b','e','f')
There are some requirements that I cannot mutate or re assigning the parameter at all.
What's the best way to approach this recursion?
I can solve this if it was list of numbers, but having a problem with this one.
I was able to come up with this recursive strategy. A noob strategy, I guess. :P
a = ('c','b','z','e','m','f','j')
def recFunc(a, theIndex):
if theIndex%2 == 1:
if theIndex < len(a):
value = recFunc(a, theIndex+1)
return (a[theIndex], ) + value
else:
return ()
else:
return (recFunc(a, theIndex+1))
print(recFunc(a, 0))
It seems to be self-explanatory. :)
Note: Maximum depth reaches at ~1000 elements.
EDIT: If you cannot add any other parameter and change it, how about such a solution (inspired from your work)?
def recFunc(a):
if len(a) == 0 or len(a) == 1:
return ()
# print(a)
return (a[1],) + recFunc(a[2:])
Don't you want just something like this?
tup = tuple(item for i, item in enumerate(tup) if i % 2 == 1)
Recursive function is unnecessary here. If you want to operate with tuple() items I would recommend you to cast it to list().
Also I'm not sure what you are trying to achieve here:
if tup.index(tup[0])+1 % 2 == 0:
tup[0] returns first element
tup.index(tup[0]) returns index of first element => 0
then 0+1 % 2 == 0 is always False
Edit:
But recursive function that returns tuple of "even" index values could look like this:
def even(tup):
if len(tup) <= 1:
return
elif len(tup) <= 3:
return tup[1]
return (tup[1], *even(tup[2:]))
Trying to return all odd numbers from a nested list using recursion. Not too sure what I am doing wrong here.
def return_odds(a):
odd = []
if isinstance(a, list):
for item in a:
if isinstance(item, list):
return_odds(item)
if isinstance(item, int):
if item % 2 == 1:
odd.append(item)
if isinstance(a, int):
if a % 2 == 1:
odd.append(a)
return odd
You're dropping the returned value from your recursion.
A typical recursive function looks something like this:
def factorial(n):
if n == 1:
return 1
else:
return n * factorial(n-1)
In your example, when you recurse and call return_odds(item), your not using the returned value. Try this instead:
def return_odds(a):
odd = []
if isinstance(a, list):
for item in a:
if isinstance(item, list):
odd += return_odds(item)
if isinstance(item, int):
if item % 2 == 1:
even_list.append(item)
if isinstance(a, int):
if a % 2 == 1:
odd.append(a)
return odd
Note that the return value of return_odds(item) is appended to your odd list.
There are two errors in your code.
Your errors
First you throw away the return value of your recursive call. Instead, extend your list odd with the returned value.
return_odds(item)
# replace by: odd.extend(return_odds(item))
Second, you have a variable even_list that appears nowhere. You probably meant to use the existing list odd.
even_list.append(item)
# replace by: odd.append(item)
Improvement
That being said, there is still a conceptual error in your code: *it will accept a single int and return it in a list*. This does not seem to be part of your requirements. Instead, loop though your input a and do a recursive call when encoutering a list.
def return_odds(a):
odd_numbers = []
for i in a:
if isinstance(i, list):
odd_numbers.extend(return_odds(i))
elif isinstance(i, int) and i % 2:
odd_numbers.append(i)
# You might also want to determine the behaviour if i is not an int
return odd_numbers
Example
print(return_odds([1, 2, 3, [4, 5, 6, [7, 8, 9]]]))
Output
[1, 3, 5, 7, 9]