How does recursion access nested lists? - python

def count_even(obj):
"""
Return the number of even numbers in obj or sublists of obj
if obj is a list. Otherwise, if obj is a number, return 1
if it is an even number and 0 if it is an odd number.
#param int|list obj: object to count even numbers from
#rtype: int
>>> count_even(3)
0
>>> count_even(16)
1
>>> count_even([1, 2, [3, 4], 5])
2
"""
count = 0
if isinstance(obj, int):
if obj % 2 == 0:
return 1
else:
return 0
else:
for i in obj:
count += count_even(i)
return new
I don't understand how in the 2nd-last line "count+= count_even(i)", "recursion" is able to access, for example, the nested list [3,4] from [1,2,[3,4],5].
Wouldn't the for loop go through each item { i=0 (1), i=1 (2), i=2 ([3,4]), i=3 (5) }, looking for an int, and not have the if statement trigger for [3,4], since it's a list?

The function is able to access the nested list [3, 4] because, as you stated, the value [3, 4] skips over the first if (because [3, 4] is not an int) and so then executes the else. In the else, you will get another loop over [3, 4] which will then check 3 and 4 for odd/evenness.
here’s a trace to help you sort things out:
obj = [ 1, 2, [3, 4], 5 ]
count_even(obj) =>
count_even([ 1, 2, [3, 4], 5]) =>
is obj an `int`? No =>
for i in [ 1, 2, [3, 4], 5] =>
count_even(1) =>
is 1 an int? Yes => return 0 because 1 is odd
count_even(2)
is 2 an int? Yes => return 1 because 2 is even
count_even([3, 4]) =>
is [3, 4] an int? No =>
for i in [3, 4] =>
count_even(3) =>
Is 3 an int? Yes => return 0 because 3 is odd
count_even(4) =>
Is 4 and int? Yes => return 1 because 4 is even
count_even(5) =>
is 5 an int? Yes => return 0 because 5 is odd

Related

find count of guesses with each element in code list but with different position python

I am implementing a function named wrong_position(guess, code), which takes in the guessed number combination in the form of a list, (guess,) and the real combination in another list, (code), and returns how many numbers are correct but in the wrong place.
I have done so far :
def wrong_position(guess, code):
if guess.count(guess[0]) == len(guess):
return 0
count = 0
copy_code = []
copy_guess = []
for c in code:
copy_code.append(c)
for g in guess:
copy_guess.append(g)
for c in copy_guess:
if c in copy_code:
index1 = copy_guess.index(c)
index2 = copy_code.index(c)
if index1 != index2:
copy_code[index2] = "*"
count += 1
else:
copy_code[index2] = "*"
return count```
but it failing following test cases
In test nr 12 the function 'wrong_position fails',
for code [2, 3, 3, 2] and guess [1, 1, 1, 2] it gives result 1 instead of 0
In test nr 13 the function 'wrong_position fails',
for code [2, 3, 3, 2] and guess [1, 1, 3, 2] it gives result 2 instead of 0
In test nr 17 the function 'wrong_position fails',
for code [9, 9, 9, 3] and guess [3, 9, 9, 2] it gives result 2 instead of 1
In test nr 20 the function 'wrong_position fails',
for code [3, 5, 4, 4] and guess [1, 4, 2, 4] it gives result 2 instead of 1
i have given many hours to sort it out but failed
i just change following and works,Thanks
if index1 != index2:
to
if index1 != index2 and c != copy_code[i]:

Can anyone help me understand how this for loop is running?

I am pretty familiar with the enumerate and 'range(len(iterable)' way of looping through a for loop. However, for whatever reason I can't seem to understand why the for loop is producing the following output.
lst = [-2, 0, 4, 5, 1, 2]
for num, b in enumerate(lst):
print(lst[b])
Output :
1
-2
1
2
0
4
I understand if I were to print(lst[num]) it would print the items of the list.
If I were to print(i) I would also print the items of the list.
If I print(num) I would print the indices.
I just can't figure out where the output is getting the numbers from.
For the enumerate function, b refers to the elements. But since the elements are also valid indices for the loop, they return a value.
SO:
lst = [-2, 0, 4, 5, 1, 2]
for num, b in enumerate(lst):
print(lst[b])
In this Every iteration is:
1) b = -2 => print(lst[b]) => lst[-2] => 1
2) b = 0 => print(lst[b]) => lst[0] => -2
3) b = 4 => print(lst[b]) => lst[4] => 1
4) b = 5 => print(lst[b]) => lst[5] => 2
5) b = 1 => print(lst[b]) => lst[1] => 0
6) b = 2 => print(lst[b]) => lst[2] => 4
Hence this is valid
lst = [-2, 0, 4, 5, 1, 2]
for index, value in enumerate(lst):
print(value)
# Prints each value
for index, value in enumerate(lst):
print(index)
# Prints each index
for index, value in enumerate(lst):
print(lst[index])
# Prints each value (but not really benefiting from enumerate)
for index, value in enumerate(lst):
print(lst[value])
# Meaningless
# Only works since value itself is an int
# Prints some element in lst whose index equals to value
If you're confused about why a piece of code is doing what it doing, it's frequently helpful to have it print out exactly what it's doing. In this case, printing out the values of b:
>>> lst = [-2, 0, 4, 5, 1, 2]
>>> for b in lst:
... print(f"lst[{b}] = {lst[b]}")
...
lst[-2] = 1
lst[0] = -2
lst[4] = 1
lst[5] = 2
lst[1] = 0
lst[2] = 4
As you can see, the b values go through the lst elements in order, and the lst[b] values that get printed on the right (which are the only values you printed originally) do indeed correspond to what you get by indexing lst.
Note that lists are zero-indexed, so lst[0] is the first element (-2), and a negative index counts that many spaces from the end, so lst[-2] is the second element from the end (1, the same as lst[4]).

Storing list of lists in matrix format [duplicate]

I have a list of lists:
a = [[1, 3, 4], [2, 5, 7]]
I want the output in the following format:
1 3 4
2 5 7
I have tried it the following way , but the outputs are not in the desired way:
for i in a:
for j in i:
print(j, sep=' ')
Outputs:
1
3
4
2
5
7
While changing the print call to use end instead:
for i in a:
for j in i:
print(j, end = ' ')
Outputs:
1 3 4 2 5 7
Any ideas?
Iterate through every sub-list in your original list and unpack it in the print call with *:
a = [[1, 3, 4], [2, 5, 7]]
for s in a:
print(*s)
The separation is by default set to ' ' so there's no need to explicitly provide it. This prints:
1 3 4
2 5 7
In your approach you were iterating for every element in every sub-list and printing that individually. By using print(*s) you unpack the list inside the print call, this essentially translates to:
print(1, 3, 4) # for s = [1, 3, 4]
print(2, 5, 7) # for s = [2, 5, 7]
oneliner:
print('\n'.join(' '.join(map(str,sl)) for sl in l))
explanation:
you can convert list into str by using join function:
l = ['1','2','3']
' '.join(l) # will give you a next string: '1 2 3'
'.'.join(l) # and it will give you '1.2.3'
so, if you want linebreaks you should use new line symbol.
But join accepts only list of strings. For converting list of things to list of strings, you can apply str function for each item in list:
l = [1,2,3]
' '.join(map(str, l)) # will return string '1 2 3'
And we apply this construction for each sublist sl in list l
You can do this:
>>> lst = [[1, 3, 4], [2, 5, 7]]
>>> for sublst in lst:
... for item in sublst:
... print item, # note the ending ','
... print # print a newline
...
1 3 4
2 5 7
a = [[1, 3, 4], [2, 5, 7]]
for i in a:
for j in i:
print(j, end = ' ')
print('',sep='\n')
output:
1 3 4
2 5 7
lst = [[1, 3, 4], [2, 5, 7]]
def f(lst ):
yield from lst
for x in f(lst):
print(*x)
using "yield from"...
Produces Output
1 3 4
2 5 7
[Program finished]
There is an alternative method to display list rather than arranging them in sub-list:
tick_tack_display = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
loop_start = 0
count = 0
while loop_start < len(tick_tack_display):
print(tick_tack_display[loop_start], end = '')
count +=1
if count - 3 == 0:
print("\n")
count = 0
loop_start += 1
OUTPUT :
123
456
789
I believe this is pretty simple:
a = [[1, 3, 4], [2, 5, 7]] # defines the list
for i in range(len(a)): # runs for every "sub-list" in a
for j in a[i]: # gives j the value of each item in a[i]
print(j, end=" ") # prints j without going to a new line
print() # creates a new line after each list-in-list prints
output
1 3 4
2 5 7
def print_list(s):
for i in range(len(s)):
if isinstance(s[i],list):
k=s[i]
print_list(k)
else:
print(s[i])
s=[[1,2,[3,4,[5,6]],7,8]]
print_list(s)
you could enter lists within lists within lists ..... and yet everything will be printed as u expect it to be.
Output:
1
2
3
4
5
6
7
8
There's an easier one-liner way:
a = [[1, 3, 4], [2, 5, 7]] # your data
[print(*x) for x in a][0] # one-line print
And the result will be as you want it:
1 3 4
2 5 7
Make sure you add the [0] to the end of the list comprehension, otherwise, the last line would be a list of None values equal to the length of your list.

Generate random array of integers with a number of appearance of each integer

I need to create a random array of 6 integers between 1 and 5 in Python but I also have another data say a=[2 2 3 1 2] which can be considered as the capacity. It means 1 can occur no more than 2 times or 3 can occur no more than 3 times.
I need to set up a counter for each integer from 1 to 5 to make sure each integer is not generated by the random function more than a[i].
Here is the initial array I created in python but I need to find out how I can make sure about the condition I described above. For example, I don't need a solution like [2 1 5 4 5 4] where 4 is shown twice or [2 2 2 2 1 2].
solution = np.array([np.random.randint(1,6) for i in range(6)])
Even if I can add probability, that should work. Any help is appreciated on this.
You can create an pool of data that have the most counts and then pick from there:
import numpy as np
a = [2, 2, 3, 1, 2]
data = [i + 1 for i, e in enumerate(a) for _ in range(e)]
print(data)
result = np.random.choice(data, 6, replace=False)
print(result)
Output
[1, 1, 2, 2, 3, 3, 3, 4, 5, 5]
[1 3 2 2 3 1]
Note that data is array that has for each element the specified count, then we pick randomly from data this way we ensure that you won't have more elements that the specify count.
UPDATE
If you need that each number appears at least one time, you can start with a list of each of the numbers, sample from the rest and then shuffle:
import numpy as np
result = [1, 2, 3, 4, 5]
a = [1, 1, 2, 0, 1]
data = [i + 1 for i, e in enumerate(a) for _ in range(e)]
print(data)
result = result + np.random.choice(data, 1, replace=False).tolist()
np.random.shuffle(result)
print(result)
Output
[1, 2, 3, 3, 5]
[3, 4, 2, 5, 1, 2]
Notice that I subtract 1 from each of the original values of a, also the original 6 was change to 1 because you already have 5 numbers in the variable result.
You could test your count against a dictionary
import random
a = [2, 2, 3, 1, 2]
d = {idx: item for idx,item in enumerate(a, start = 1)}
l = []
while len(set(l) ^ set([*range(1, 6)])) > 0:
l = []
while len(l) != 6:
x = random.randint(1,5)
while l.count(x) == d[x]:
x = random.randint(1,5)
l.append(x)
print(l)

How to determine if a list contains either 3 even or 3 odd values next to each other?

How do you determine if a list contains either 3 even or 3 odd values all next to each other?
Example lists (True, False, True):
[2, 1, 3, 5]
[2, 1, 2, 5]
[2, 4, 2, 5]
Closest code:
evenOdd = []
while True:
try:
n = int(input())
evenOdd.append(n)
except:
break
for x in evenOdd:
if x % 2 == 0:
print("True")
Here is some code. This is considered more "pythonic" than iterating over indices--this iterates over consective-triples, using the zip function. This will give an error if the list has fewer than three items--you can add that error check. The zip function stops when one of the iterables runs out of values, which is exactly what we want here.
def three_evens_or_odds(alist):
for a, b, c in zip(alist, alist[1:], alist[2:]):
if (((a & 1) and (b & 1) and (c & 1)) or
((a & 1 == 0) and (b & 1 == 0) and (c & 1 == 0))):
return True
return False
print(three_evens_or_odds([2, 1, 3, 5]))
print(three_evens_or_odds([2, 1, 2, 5]))
print(three_evens_or_odds([2, 4, 2, 5]))
Or, even shorter (borrowing an idea from #jdehesa which I should have thought of on my own, so upvote his answer as I did),
def three_evens_or_odds(alist):
for a, b, c in zip(alist, alist[1:], alist[2:]):
if a & 1 == b & 1 == c & 1:
return True
return False
print(three_evens_or_odds([2, 1, 3, 5]))
print(three_evens_or_odds([2, 1, 2, 5]))
print(three_evens_or_odds([2, 4, 2, 5]))
The printout from that is
True
False
True
You can use itertools.groupby():
from itertools import groupby
def check_list(lst):
for k, g in groupby(lst, key=lambda x: x % 2):
if len(list(g)) == 3:
return True
return False
print(check_list([2, 1, 3, 5])) # True
print(check_list([2, 1, 2, 5])) # False
print(check_list([2, 4, 2, 5])) # True
This can be easily adjusted for any group size.
You can iterate through the list of numbers in blocks of three:
def hasThreeContiguousEvenOrOdd(numbers):
for i in range(len(numbers) - 2):
a, b, c = numbers[i:i + 3]
if a % 2 == 0 and b % 2 == 0 and c % 2 == 0:
return True
elif a % 2 == 1 and b % 2 == 1 and c % 2 == 1:
return True
return False
numbers1 = [2, 1, 3, 5]
numbers2 = [2, 1, 2, 5]
numbers3 = [2, 4, 2, 5]
print(numbers1, hasThreeContiguousEvenOrOdd(numbers1))
print(numbers2, hasThreeContiguousEvenOrOdd(numbers2))
print(numbers3, hasThreeContiguousEvenOrOdd(numbers3))
Output:
[2, 1, 3, 5] True
[2, 1, 2, 5] False
[2, 4, 2, 5] True
If you want to be more idiomatic or "pythonic" you can improve the code and do for example something like this:
def hasThreeContiguousEvenOrOdd(numbers):
for a, b, c in zip(numbers, numbers[1:], numbers[2:]):
if a % 2 == b % 2 == c % 2:
return True
return False
One more short and generic solution:
def consecutive_evenodd(lst, n=3):
n_uplets = ( lst[i:i+n] for i in range(len(lst)-n+1) )
return any( sum(el % 2 for el in n_uplet) % n == 0 for n_uplet in n_uplets )
# test
inputs = [[2, 1, 3, 5],
[2, 1, 2, 5],
[2, 4, 2, 5]]
for lst in inputs:
print(lst, consecutive_evenodd(lst))
output:
[2, 1, 3, 5] True
[2, 1, 2, 5] False
[2, 4, 2, 5] True
Some explanation: The sum(...) part gives the number of odd number in each n-uplet. When all numbers are odd or even, this sum is equal to either n or zero. For the other cases, the result of the sum falls in-between. So, sum(...) % n is equal to 0 only when all the n-uplet numbers are either odd or even.
If you are looking for exact 3 of odd or even in a list of 4 element:
def ex(l):
return sum([1 if item%2 ==0 else -1 for item in l]) in [2, -2]
ex([2, 1, 3, 5]) # True
ex([2, 1, 2, 5]) # False
ex([2, 4, 2, 5]) # True
And if list length and number of odd or even elements are parameters you can change 2 and -2 to a parameter.
one way with two int counters:
Time: O(n)
space: O(1)
function:
def chk(alist):
odd=even=0
for n in alist:
if n % 2:
odd += 1
even = 0
else:
even += 1
odd = 0
if odd>2 or even>2:
return True
return False
3 lists from your example output True False True. (tested with python2)
Tried a simple way to do it. Maintain two flags for even and odd. If you find an even, increment the even flag and reset the odd flag, and vice versa. As soon as one flag's value becomes 3, you know you have found three in succession.
evenodd = []
while True:
try:
n = int(input())
evenodd.append(n)
except:
break
evenflag = 0
oddflag = 0
print(evenodd)
for number in evenodd:
if number % 2 == 0:
evenflag += 1
oddflag = 0
else:
oddflag += 1
evenflag = 0
if evenflag == 3:
print("Found 3 consecutive even numbers")
break
elif oddflag == 3:
print ("Found three consecutive odd numbers")
break
Use zip to create n element tuples (3 in our case), the use all(map(lambda x: x%2, sl) to find if all the 3 elements in the tuples are odd and then use any to check if there is atleast one match.
Using any and all would guarantee minimal number of odd or even checks needed
>>> n =3
>>> three_odds_or_even = lambda lst: any(all(map(lambda x: x%2, sl)) or all(map(lambda x: not x%2, sl)) for sl in zip(*(lst[i:] for i in range(n))))
>>> three_odds_or_even([2, 1, 3, 5])
True
>>> three_odds_or_even([2, 1, 2, 5])
False
>>> three_odds_or_even([2, 4, 2, 5])
True
>>>
Here is a solution using a simple for loop.
The idea is to maintain a list, whose values depend on whether elements in the input list are even or odd. Clear the list when you don't have a consecutive odd/even.
If at any point you have 3 items in your tracker list, the function returns True.
L1 = [2, 1, 3, 5]
L2 = [2, 1, 2, 5]
L3 = [2, 4, 2, 5]
def even_odd_consec(x, k=3):
lst = []
for item in x:
is_odd = item % 2
if not (lst and (lst[-1] == is_odd)):
lst.clear()
lst.append(is_odd)
if len(lst) == k:
return True
return False
even_odd_consec(L1, 3) # True
even_odd_consec(L2, 3) # False
even_odd_consec(L3, 3) # True
Just checks that odd/even holds as long as the minimum sequence length requested, 3 in this case.
def determine(list_, in_a_row=3):
prv, cntr = None, 1
for v in list_:
cur = bool(v % 2)
if prv is cur:
cntr += 1
else:
cntr = 1
prv = cur
if cntr >= in_a_row:
return True
return False
dataexp = [
([2, 1, 3, 5],True),
([2, 1, 2, 5],False),
([2, 4, 2, 5],True),
#hmmm, you're able to handle lists smaller than 3, right?
([],False),
]
for li, exp in dataexp:
got = determine(li)
msg = "exp:%s:%s:got for %s" % (exp, got, li)
if exp == got:
print("good! %s" % msg)
else:
print("bad ! %s" % msg)
output
good! exp:True:True:got for [2, 1, 3, 5]
good! exp:False:False:got for [2, 1, 2, 5]
good! exp:True:True:got for [2, 4, 2, 5]
good! exp:False:False:got for []

Categories