I have a question about the below code, particularly the 6th line; is it right to say that it is returning the index of target-nums[I]? If so, why is there another I after it?
Also, what is comp[nums[I]] = I doing? Is it assigning values of nums into comp if it is not in comp already?
Finally, what is the final return [ ] doing in the last line of code?
def TwoSum(nums, target):
comp = {}
for i in range(len(nums)):
if (target - nums[i]) in comp:
return [comp[target - nums[i]],i]
comp[nums[i]] = i
return []
print(TwoSum(nums,target))
is it right to say that it is returning the index of target-nums[I]?
If so, why is there another 'I' after it?
It is returning a list of two items, the first item being comp[target - nums[i]], and the second item being i. It's the same idea as:
def addAndSubtract(x, y):
return [x+y, x-y]
Above, we return a list, the first item in the list is the value of evaluating x+y and the second value is the result of evaluating x-y.
Also, what is comp[nums[I]] = I doing? Is it assigning values of nums into comp > if it is not in comp already?
This will assign the value of nums[i] as a key in your comp dictionary and assign it the value of i. It essentially stores the current value in nums and along with its index. This does two things:
Allows you to easily and quickly check if you have seen a given number yet by checking if it is a key in your comp dictionary
Allows you to check where that number was last seen in your list.
The comp[nums[i]] = i occurs each time your for loop runs, so it will do it for all numbers, in your list, unless it returns in your if-statement. If you happen to encounter the same number again (which is already in your list), then this assignment will simply overwrite the value with the current index of the current number (ie: i).
Finally, what is the final return [ ] doing in the last line of code?
The purpose of this is to return an empty list. It is just a way to signify that no result was found. You will only reach that return when you have iterated through all the numbers in your list and not returned from within your for loop, thus indicating no sum can be made to reach the target.
I explain how this algorithm works in detail here, so you might want to check that out if you need more of an explanation. Although the question is a JavaScript question, the logic explained is the exact same as this.
Related
So I was trying to complete this kata on code wars and I ran across an interesting solution. The kata states:
"Given an array of integers, find the one that appears an odd number of times.
There will always be only one integer that appears an odd number of times."
and one of the solutions for it was:
def find_it(seq):
return [x for x in seq if seq.count(x) % 2][0]
My question is why is there [0] at the end of the statement. I tried playing around with it and putting [1] instead and when testing, it passed some tests but not others with no obvious pattern.
Any explanation will be greatly appreciated.
The first brackets are a list comprehension, the second is indexing the resulting list. It's equivalent to:
def find_it(seq):
thelist = [x for x in seq if seq.count(x) % 2]
return thelist[0]
The code is actually pretty inefficient, because it builds the whole list just to get the first value that passed the test. It could be implemented much more efficiently with next + a generator expression (like a listcomp, but lazy, with the values produced exactly once, and only on demand):
def find_it(seq):
return next(x for x in seq if seq.count(x) % 2)
which would behave the same, with the only difference being that the exception raised if no values passed the test would be IndexError in the original code, and StopIteration in the new code, and it would operate more efficiently by stopping the search the instant a value passed the test.
Really, you should just give up on using the .count method and count all the elements in a single pass, which is truly O(n) (count solutions can't be, because count itself is O(n) and must be called a number of times roughly proportionate to the input size; even if you dedupe it, in the worst case scenario all elements appear twice and you have to call count n / 2 times):
from collections import Counter
def find_it(it):
# Counter(it) counts all items of any iterable, not just sequence,
# in a single pass, and since 3.6, it's insertion order preserving,
# so you can just iterate the items of the result and find the first
# hit cheaply
return next(x for x, cnt in Counter(it).items() if cnt % 2)
That list comprehension yields a sequence of values that occur an odd number of times. The first value of that sequence will occur an odd number of times. Therefore, getting the first value of that sequence (via [0]) gets you a value that occurs an odd number of times.
Happy coding!
That code [x for x in seq if seq.count(x) % 2] return the list which has 1 value appears in input list an odd numbers of times.
So, to make the output as number, not as list, he indicates 0th index, so it returns 0th index of list with one value.
There is a nice another answer here by ShadowRanger, so I won't duplicate it providing partially only another phrasing of the same.
The expression [some_content][0] is not a double list. It is a way to get elements out of the list by using indexing. So the second "list" is a syntax for choosing an element of a list by its index (i.e. the position number in the list which begins in Python with zero and not as sometimes intuitively expected with one. So [0] addresses the first element in the list to the left of [0].
['this', 'is', 'a', 'list'][0] <-- this an index of 'this' in the list
print( ['this', 'is', 'a', 'list'][0] )
will print
this
to the stdout.
The intention of the function you are showing in your question is to return a single value and not a list.
So to get the single value out of the list which is built by the list comprehension the index [0] is used. The index guarantees that the return value result is taken out of the list [result] using [result][0] as
[result][0] == result.
The same function could be also written using a loop as follows:
def find_it(seq):
for x in seq:
if seq.count(x) % 2 != 0:
return x
but using a list comprehension instead of a loop makes it in Python mostly more effective considering speed. That is the reason why it sometimes makes sense to use a list comprehension and then unpack the found value(s) out of the list. It will be in most cases faster than an equivalent loop, but ... not in this special case where it will slow things down as mentioned already by ShadowRanger.
It seems that your tested sequences not always have only one single value which occurs an odd number of times. This will explain why you experience that sometimes the index [1] works where it shouldn't because it was stated that the tested seq will contain one and only one such value.
What you experienced looking at the function in your question is a failed attempt to make it more effective by using a list comprehension instead of a loop. The actual improvement can be achieved but by using a generator expression and another way of counting as shown in the answer by ShadowRanger:
from collections import Counter
def find_it(it):
return next(x for x, cnt in Counter(it).items() if cnt % 2)
Make a function that receives a string containing only digits and may also be an empty string, which returns an integer value which is the maximum of all the digits that are in the EVEN POSITIONS of the original string.
If the empty string, the function should return -1.
For example:
max_even_pos("123454321") returns 5, because 5 is the maximum of 1,3,5,3,1, which are the digits in the original string in even positions.
# My code
def max_even_pos(st):
if not st:
return -1 ### This line satisfies the empty list condition
for i in range(len(st)): ### Problem I have. Trying to find
## the max integer from even positions
num_list = [i] # assigns elements to the list
if i%2 == 0: # checks if elements are even
return max(num_list) # result
My only problem is trying to get the code to find the greatest integer in the even position of the original string. I think "num_list = [i]" causes the error, but I am unsure how to change this so it executes properly.
As of right now, it outputs 0 for all cases
Your current code ensures that num_list has no more than a single element. When you hit the first even index, 0, you stop and return that index, without regard to the input value. You have several errors to correct:
Put the return after the loop. You have to get through all of the input before you can return the required value.
Accumulate the values with append. Your current code keeps only the last one.
Accumulate the input values; i is the position, not the value. I believe that you want st[i]
Also look into better ways to iterate through a list. Look at for loops or list slicing with a step of 2. If you are ready for another level of learning, look up list comprehension; you can reduce this function to a one-line return.
#Prune is correct. Maybe comparing the lines below to your original will help you for next time....
test_string = "123454321"
def max_even_pos(st):
num_list = []
if not st:
return -1
for i in range(len(st)):
if i%2 == 0:
num_list.append(st[i])
return max(num_list)
print(max_even_pos(test_string))
So i'm studying recursion and have to write some codes using no loops
For a part of my code I want to check if I can sum up a subset of a list to a specific number, and if so return the indexes of those numbers on the list.
For example, if the list is [5,40,20,20,20] and i send it with the number 60, i want my output to be [1,2] since 40+20=60.
In case I can't get to the number, the output should be an empty list.
I started with
def find_sum(num,lst,i,sub_lst_sum,index_lst):
if num == sub_lst_sum:
return index_lst
if i == len(sum): ## finished going over the list without getting to the sum
return []
if sub_lst_sum+lst[i] > num:
return find_sum(num,lst,i+1,sub_lst_sum,index_lst)
return ?..
index_lst = find_sum(60,[5,40,20,20,20],0,0,[])
num is the number i want to sum up to,
lst is the list of numbers
the last return should go over both the option that I count the current number in the list and not counting it.. (otherwise in the example it will take the five and there will be no solution).
I'm not sure how to do this..
Here's a hint. Perhaps the simplest way to go about it is to consider the following inductive reasoning to guide your recursion.
If
index_list = find_sum(num,lst,i+1)
Then
index_list = find_sum(num,lst,i)
That is, if a list of indices can be use to construct a sum num using elements from position i+1 onwards, then it is also a solution when using elements from position i onwards. That much should be clear. The second piece of inductive reasoning is,
If
index_list = find_sum(num-lst[i],lst,i+1)
Then
[i]+index_list = find_sum(num,lst,i)
That is, if a list of indices can be used to return a sum num-lst[i] using elements from position i+1 onwards, then you can use it to build a list of indices whose respective elements sum is num by appending i.
These two bits of inductive reasoning can be translated into two recursive calls to solve the problem. Also the first one I wrote should be used for the second recursive call and not the first (question: why?).
Also you might want to rethink using empty list for the base case where there is no solution. That can work, but your returning as a solution a list that is not a solution. In python I think None would be a the standard idiomatic choice (but you might want to double check that with someone more well-versed in python than me).
Fill in the blanks
def find_sum(num,lst,i):
if num == 0 :
return []
elif i == len(lst) :
return None
else :
ixs = find_sum(???,lst,i+1)
if ixs != None :
return ???
else :
return find_sum(???,lst,i+1)
Say I have a list x = [1, 2, 3, 4]
Is there a recursive method where i can go through the list to find the value?
I want to ultimately be able to compare a returned value in the list, (or nested list) to an arbitrary number to see it it matches.
I can think a way to do this using a for loop, but i have trouble imagining a recursive method to do the same thing. I know that I can't set a counter to keep track of my position in the list because calling the function recursively would just reset the counter every time.
I was thinking I could set my base case of the function as a comparison between the number and a list of len 1.
I just want some hints really.
This is not the way to do things in Python, but surely - you can traverse a list of lists recursively:
def findList(lst, ele):
if not lst: # base case: the list is empty
return False
elif lst[0] == ele: # check if current element is the one we're looking
return True
elif not isinstance(lst[0], list): # if current element is not a list
return findList(lst[1:], ele)
else: # if current element is a list
return findList(lst[0], ele) or findList(lst[1:], ele)
Recursive functions are idiomatic for when you have a linked list. Python lists are more like arrays. But it's still possible to handle a Python list with a recursive function -- there's no real utility, but it can be interesting as an exercise.
You start with a full list, and your base case is when the list is empty. Traverse the list by passing the list in as an argument, using x.pop() to simultaneously fetch and remove the first item in the list, evaluate the popped item, and then pass the list (now shorter) into the same function.
Edit: actually, on second thought, you would be better off not using x.pop() and instead peeking at the first value and passing the remainder in a slice. This would be grossly inefficient, because you're copying the list every time you slice, but it's better than destructively consuming the list inside your recursive function, unless that's a desired side-effect.
Well you will have two base cases:
1) You have reached the end of the list => return false.
2) Your current element is the element you are looking for => return true (or the element or its position, whatever you are interested in).
The thing you have to do all the time is check both base cases on the current element and apply the function recursively on the next element in the list if neither one of the base cases applied.
The input (list) would be a list similar to [[1,2],[5,6],[4,6]]. I am trying to add the whole row together to test if it is even or odd.
def evenrow(list):
for row in list:
for item in row:
newNums+=item
n=sum(newNums)
print(n)
First of all do not use 'list' as variable name. Second you calling sum for int value not for a list and that's why you getting error. Check your code please.
Not sure but your code can looks like:
def evenrow(list):
for row in list:
value = sum(row)
if values is even: # put your condition here
# do something
else:
print "Value is odd"
Just an alternate method:
def evenrow(lst):
return sum(map(sum,lst))%2 == 0 #True if even, False otherwise.
This works this way:
The outer sum adds up all items of the map, which applies sum to each item in lst. In python2, map returns a list object, while in python3, it returns a map object. This is passed to the outer sum function, which adds up all items in your map.
def evenrow(lst):
return sum(itertools.chain(*a)) % 2 == 0
This expands all the items in a (each of the sublists), and chains them together, as a chain object. It then adds together all the items and determines if the sum is even.
You don't need the following line of code: n=sum(newNums). You already summed up all the items of row in the newNums += item line. Second, you have to declare newNums before using it in your code. So, the fixed version of code will look like this:
def evenrow(list):
for row in list:
newNums = 0
for item in row:
newNums += item
print(newNums)
BTW: You should consider accepting answers to some of your previous questions, otherwise nobody will spend their time to answer your new questions.