Python - List Binary Search without bisect - python

I have a list and I want to binary_search a key(number).
My code is below but I don't have a clue what to do where the bold text on code is:
(What to do with this? Is an other function? int imid = midpoint(imin, imax))
List = []
x = 1
#Import 20 numbers to list
for i in range (0,20):
List.append (i)
print (List)
key = input("\nGive me a number for key: ")
def midpoint(imin, imax):
return point((imin+imax)/2)
def binary_search(List,key,imin,imax,point):
while (imax >= imin):
int imid = midpoint(imin, imax)
if(List[imid] == key):
return imid;
elif (List[imid] < key):
imin = imid + 1;
else:
imax = imid - 1;
return KEY_NOT_FOUND;
print (binary_search(key))
midpoint(imin, imax)
binary_search(List,key,imin,imax,point)

It doesn't seem to be doing anything for you; remove the call to midpoint, and point, and just have
def binary_search(List,key,imin,imax,point):
while (imax >= imin):
imid = (imin + imax) / 2
(However, there are some things wrong with your code, and it won't work with just that change;
You create a list called List then try to append to an uninitialized variable called myList
You 'import 20 random' numbers, but range() is not random, it's a simple sequence 1, 2, 3, 4...
range already returns a list, no need to count through it and copy it, just use it
You call binary_search with an empty List, a key, and three uninitialized variables
binary_search assumes the list is sorted, which it is, but if the comment about 'random numbers' was correct, it wouldn't be.
)

Related

is there anyway of getting a values index in an iterable when using functools.reduce in python

I have a function that would benefit from using functools.reduce it would act something like this
import functools
def add(total, val, max_index, index):
if index > max_index:
return total
else:
return total + val
arr = [1,2,3,4,5,6,7,8]
functools.reduce(functools.partial(add, max_index=5), arr, 0)
how do I pass the index of the val in the arr into the function or is it just not possible
I thought about using a global variable to track the index but of course would much rather not
by the way my function is meant to be used for an array a lot larger than an array of len 8
You could always pass enumerate(arr) which transforms any iterable of elements X_i into another of elements (i,X_i).
Then the function would need to unpack the "value" it received (which is now a 2-tuple) into index and value.
Example:
import functools
def add(total, index_val, max_index):
index, val = index_val
if index > max_index:
return total
else:
return total + val
arr = [1,2,3,4,5,6,7,8]
res = functools.reduce(functools.partial(add, max_index=5), enumerate(arr,0), 0)
print(res)
Python reduce function is removed from global namespace to functools and general instruction is to use list comprehension instead. Using list-comprehensions I would do it like this:
arr = [1,2,3,4,5,6,7,8]
max_index = 5
# 0-based index
print( sum([val for index, val in enumerate(arr,0) if index<=max_index]) )
# output is 21

IndexError: list index out of range - python 3.8

Alright. I have seen quite a few questions like this on StackOverflow, but none really helped me. I am working on a python script that moves some base32 code around. Here is the problematic function:
def getCode():
i = 0
j = 0
k = 0
base32 = input("Please paste your code below:\n")
base32 = base32.split("#")
while i < len(base32):
base32[i] = base32[i].split(",")
i += 1
while j < len(base32[i]):
base32[i[j]] = base32[i[j]].split(" ")
j += 1
while k < len(base32[i[j]]):
if base32[i[[j[k]]]] == "":
base32.list_splice(k, 1)
k += 1
if base32[i[j]].len() == 0:
base32[i].list_splice(j, 1)
return base32
I defined list_splice() earlier. I also declared getCode() after this. When I run it, it asks me for my code, but when I hit enter after, it gives me this:
Traceback (most recent call last):
File "C:\Users\gabri\SynologyDrive\track_mover.py", line 43, in <module>
getCode()
File "C:\Users\gabri\SynologyDrive\track_mover.py", line 32, in getCode
while j < len(base32[i]):
IndexError: list index out of range
I am not sure why. From what I understand, a IndexError generally refers to passing in a list index that is too high, like if you have a string with 3 characters and pass list[3]. I have no idea why it is saying this. I would think that the
while loop would keep it from getting out of hand, but maybe not? I have tried all kinds of lengths of strings that I paste into it, but that doesn't seem to be the answer.
===
EDIT
I tried Mustafa Aydın's answer, and while that does fix some things, it now outputs this:
Traceback (most recent call last):
File "C:\Users\gabri\SynologyDrive\track_mover.py", line 44, in <module>
getCode()
File "C:\Users\gabri\SynologyDrive\track_mover.py", line 33, in getCode
base32[i[j]] = base32[i[j]].split(" ")
TypeError: 'int' object is not subscriptable
I have no idea why it is doing this.
I also got some questions regarding the list_splice() function. What it is is the python equivalent of the javascript .splice() built-in function. Here is the code for it:
def list_splice(target, start, delete_count=None, *items):
"""Remove existing elements and/or add new elements to a list.
target the target list (will be changed)
start index of starting position
delete_count number of items to remove (default: len(target) - start)
*items items to insert at start index
Returns a new list of removed items (or an empty list)
"""
if delete_count == None:
delete_count = len(target) - start
# store removed range in a separate list and replace with *items
total = start + delete_count
removed = target[start:total]
target[start:total] = items
return removed
If it helps any, here is the JavaScript I am converting from:
function loadCode(input) {
var base32 = document.getElementById(input).value;
var base32 = base32.split("#");
for (var i = 0; i < base32.length; i++) {
base32[i] = base32[i].split(",");
for (var j = 0; j < base32[i].length; j++) {
base32[i][j] = base32[i][j].split(" ");
for (var k = 0; k < base32[i][j].length; k++) {
if (base32[i][j][k] == "") {
base32[i][j].splice(k, 1);
}
}
if (base32[i][j].length == 0) {
base32[i].splice(j, 1);
}
}
}
return base32;
}
Thanks in advance for any help!
You should increment i after you are done with the i'th item of the base32 list. Also (response to your edit), accessing a list element in a 2-dimensional fashion is done as base32[i][j] i.e. you first reach to i'th item, then reach to j'th item of that item. Similar applies to base32[i][j][k].
Edit: Seeing your javascript code, I'd say that you should be using for loops in python also. Those will be less error prone. Also, the splicing you are doing (only removing one item) can be done with pop. Lastly, removing elements whilst iterating over a list is not a good idea; one solution is to iterate in reverse order. So, putting all these together, you end up with this:
def getCode():
base32 = input("Please paste your code below:\n")
base32 = base32.split("#")
for i in reversed(range(len(base32))):
base32[i] = base32[i].split(",")
for j in reversed(range(len(base32[i]))):
base32[i][j] = base32[i][j].split(" ")
for k in reversed(range(len(base32[i][j]))):
if base32[i][j][k] == "":
base32[i][j].pop(k)
if len(base32[i][j]) == 0:
base32[i].pop(j)
return base32
while i < len(base32):
base32[i] = base32[i].split(",")
i += 1
while j < len(base32[i]):
On the final iteration of this loop, the loop condition i < len(base32) is still true, so the loop executes one last time. But then i is incremented inside the loop, so now base32[i] is out-of-bounds.
Generally, incrementing a loop variable should be done at the bottom of the loop, so that no code executes with a possibly-too-large value of the loop variable.

Python - Adding all digits in string

How can i create a function that returns the sum of a string made up of 3 or more digits. For example, if the parameter/string is "13456". How can I return the result of (1*3 + 3*4 + 4*5 + 5*6). Thank you, all help is appreciated. Very new to python.
Another one-liner:
a = '13456'
print(sum([int(x)*int(y) for x, y in zip(a[1:], a[:-1])]))
You just need to go through the string, multiplying the actual value to the next value and add it to a variable to return it later.
def func(param):
ret = 0
for i in range(len(param)-1):
ret = ret + int(param[i]) * int(param[i+1])
return ret
my_string = "12345"
total = 0
for n in range(len(my_string) - 1):
total += int(my_string[n]) * int(my_string[n+1])
This function first turns your string into a list and then applies a map on it to convert all the elements to ints. Finally it uses a loop to access and multiply consecutive elements,
def str_sum(nstr):
nint = list(map(int, list(nstr)));
res = 0;
for i in range(len(nint[:-1])):
res += nint[i]*nint[i+1]
return res
Converting result of map into list using list(map(...)) is redundant in Python 2.7 but necessary in Python 3.X as map returns an object instead of a list.
Use range + sum
l = '13456'
sum([int(l[i])*int(l[i+1]) for i in range(len(l)-1)])
#Output:
#65
with range(len(l)-1), you can get the start, end indexes like below
Output:[0, 1, 2, 3]
Looping through the above list and indexing on list l,
int(l[i])*int(l[i+1]) # gives [1*3, 3*4 , ...]
Summing the output list
sum([1*3, 3*4 , ...]) # gives 65
def func(input):
return sum([int(input[i])*int(input[i+1]) for i in range(len(input)-1)])

python for and while loop for tuples

I'm a beginner in python and was wondering why this function doesn't work. It is syntactically correct.
This function is supposed to collect every odd tuple item and I used a for loop as follows:
def oddTuples(aTup):
result = ()
for i in aTup:
if i % 2 == 0:
result += (aTup[i],)
return result
This is the 'correct' answer using while loop.
def oddTuples(aTup):
# a placeholder to gather our response
rTup = ()
index = 0
# Idea: Iterate over the elements in aTup, counting by 2
# (every other element) and adding that element to
# the result
while index < len(aTup):
rTup += (aTup[index],)
index += 2
return rTup
If anybody can help me, it would be much appreciated!
UPDATE
Okay, I got the problem, by 'i' I was merely collecting the real value within that tuple. I've fixed that, but this code is catching only some of the odd-idexed items, not all of them....
def oddTuples(aTup):
result = ()
for i in aTup:
index = aTup.index(i)
if index % 2 == 0:
result += (aTup[index],)
return result
Your for loop is iterating over the values in aTup, not the index of the values.
It appears your want your code to iterate over the index of the values or through a range of numbers starting with 0 and ending with the length of the tuple minus one and then use that number as the index to pull the value out of the tuple.
I didn't catch it on one go since it was syntactically correct too, but the error you are having is due to you iterating over the objects of the tuple (aTup) and not the indices. See here:
for i in aTup: # <-- For each *object* in the tuple and NOT indices
if i % 2 == 0:
result += (aTup[i],)
To fix the problem, use range() and len() over the aTup so that it iterates over the indices of the tuple instead, and change the if statement accordingly:
for i in range(len(aTup)):
if aTup[i] % 2 == 0:
result += (aTup[i],)
An alternative solution is to keep your object iterations but append the object directly to the result tuple instead of indexing:
for i in aTup:
if i % 2 == 0:
result += (i,)
Hope ths helped!
The reason is you are not using index..In below code i is not an index but the element in tuple but you are calling aTup[i] assuming i is an index which is not.
The below code will work fine - No need of doing aTup[i] or range.
def oddTuples(aTup):
result = ()
for i in aTup:
if i % 2 == 0:
result += (i,)
return result
Try replacing
def oddTuples(aTup):
result = ()
for i in aTup:
index = aTup.index(i)
if index % 2 == 0:
result += (aTup[index],)
return result
With
def oddTuples(aTup):
result = ()
for i in aTup:
index = aTup.index(i)
result += (aTup[index],)
return result
To fix you issue of it only doing the even numbered ones.
In simple words , if your tuple is
tup = (1, 2, 3, 4, 5 , 1000);
When your code is checking if each item is % 2 == 0 or not which is not what you want, from your description , you want only the items with odd index
So if you try the tuple above , you will get the following error:
IndexError: tuple index out of range , because for the 1000 it satisfy your condition and will do what is said in the if , trying to add the aTup(1000) (element of index 1000 in your input tuple) which doesn't exist as the tuple is only of 6 elements to your resultTuple
For this for loop to work , you can use the following method
def oddTuples(aTup):
result = ()
for i in aTup:
index = tup.index(i) # getting the index of each element
if index % 2 == 0:
result += (aTup[index],)
print(aTup[index])
return result
# Testing the function with a tuple
if __name__ == "__main__":
tup = (1, 2, 3, 7, 5, 1000, 1022)
tup_res = oddTuples(tup)
print(tup_res)
The result of this will be
1
3
5
1022
(1, 3, 5, 1022)
Process finished with exit code 0

counting odd numbers in a list python

This is a part of my homework assignment and im close to the final answer but not quite yet. I need to write a function that counts odd numbers in a list.
Create a recursive function count_odd(l) which takes as its only argument a list of integers. The function will return a count of the number of list elements that are odd, i.e., not evenly divisible by 2.\
>>> print count_odd([])
0
>>> print count_odd([1, 3, 5])
3
>>> print count_odd([2, 4, 6])
0
>>> print count_odd([0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144])
8
Here is what i have so far:
#- recursive function count_odd -#
def count_odd(l):
"""returns a count of the odd integers in l.
PRE: l is a list of integers.
POST: l is unchanged."""
count_odd=0
while count_odd<len(l):
if l[count_odd]%2==0:
count_odd=count_odd
else:
l[count_odd]%2!=0
count_odd=count_odd+1
return count_odd
#- test harness
print count_odd([])
print count_odd([1, 3, 5])
print count_odd([2, 4, 6])
print count_odd([0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144])
Can u help explain what im missing. The first two test harness works fine but i cant get the final two. Thanks!
Since this is homework, consider this pseudo-code that just counts a list:
function count (LIST)
if LIST has more items
// recursive case.
// Add one for the current item we are counting,
// and call count() again to process the *remaining* items.
remaining = everything in LIST except the first item
return 1 + count(remaining)
else
// base case -- what "ends" the recursion
// If an item is removed each time, the list will eventually be empty.
return 0
This is very similar to what the homework is asking for, but it needs to be translate to Python and you must work out the correct recursive case logic.
Happy coding.
def count_odd(L):
return (L[0]%2) + count_odd(L[1:]) if L else 0
Are slices ok? Doesn't feel recursive to me, but I guess the whole thing is kind of against usual idioms (i.e. - recursion of this sort in Python):
def countOdd(l):
if l == list(): return 0 # base case, empty list means we're done
return l[0] % 2 + countOdd(l[1:]) # add 1 (or don't) depending on odd/even of element 0. recurse on the rest
x%2 is 1 for odds, 0 for evens. If you are uncomfortable with it or just don't understand it, use the following in place of the last line above:
thisElement = l[0]
restOfList = l[1:]
if thisElement % 2 == 0: currentElementOdd = 0
else: currentElementOdd = 1
return currentElementOdd + countOdd(restOfList)
PS - this is pretty recursive, see what your teacher says if you turn this in =P
>>> def countOdd(l):
... return fold(lambda x,y: x+(y&1),l,0)
...
>>> def fold(f,l,a):
... if l == list(): return a
... return fold(f,l[1:],f(a,l[0]))
All of the prior answers are subdividing the problem into subproblems of size 1 and size n-1. Several people noted that the recursive stack might easily blow out. This solution should keep the recursive stack size at O(log n):
def count_odd(series):
l = len(series) >> 1
if l < 1:
return series[0] & 1 if series else 0
else:
return count_odd(series[:l]) + count_odd(series[l:])
The goal of recursion is to divide the problem into smaller pieces, and apply the solution to the smaller pieces. In this case, we can check if the first number of the list (l[0]) is odd, then call the function again (this is the "recursion") with the rest of the list (l[1:]), adding our current result to the result of the recursion.
def count_odd(series):
if not series:
return 0
else:
left, right = series[0], series[1:]
return count_odd(right) + (1 if (left & 1) else 0)
Tail recursion
def count_odd(integers):
def iter_(lst, count):
return iter_(rest(lst), count + is_odd(first(lst))) if lst else count
return iter_(integers, 0)
def is_odd(integer):
"""Whether the `integer` is odd."""
return integer % 2 != 0 # or `return integer & 1`
def first(lst):
"""Get the first element from the `lst` list.
Return `None` if there are no elements.
"""
return lst[0] if lst else None
def rest(lst):
"""Return `lst` list without the first element."""
return lst[1:]
There is no tail-call optimization in Python, so the above version is purely educational.
The call could be visualize as:
count_odd([1,2,3]) # returns
iter_([1,2,3], 0) # could be replaced by; depth=1
iter_([2,3], 0 + is_odd(1)) if [1,2,3] else 0 # `bool([1,2,3])` is True in Python
iter_([2,3], 0 + True) # `True == 1` in Python
iter_([2,3], 1) # depth=2
iter_([3], 1 + is_odd(2)) if [2,3] else 1
iter_([3], 1 + False) # `False == 0` in Python
iter_([3], 1) # depth=3
iter_([], 1 + is_odd(3)) if [3] else 1
iter_([], 2) # depth=4
iter_(rest([]), 2 + is_odd(first([])) if [] else 2 # bool([]) is False in Python
2 # the answer
Simple trampolining
To avoid 'max recursion depth exceeded' errors for large arrays all tail calls in recursive functions can be wrapped in lambda: expressions; and special trampoline() function can be used to unwrap such expressions. It effectively converts recursion into iterating over a simple loop:
import functools
def trampoline(function):
"""Resolve delayed calls."""
#functools.wraps(function)
def wrapper(*args):
f = function(*args)
while callable(f):
f = f()
return f
return wrapper
def iter_(lst, count):
#NOTE: added `lambda:` before the tail call
return (lambda:iter_(rest(lst), count+is_odd(first(lst)))) if lst else count
#trampoline
def count_odd(integers):
return iter_(integers, 0)
Example:
count_odd([1,2,3])
iter_([1,2,3], 0) # returns callable
lambda:iter_(rest(lst), count+is_odd(first(lst))) # f = f()
iter_([2,3], 0+is_odd(1)) # returns callable
lambda:iter_(rest(lst), count+is_odd(first(lst))) # f = f()
iter_([3], 1+is_odd(2)) # returns callable
lambda:iter_(rest(lst), count+is_odd(first(lst))) # f = f()
iter_([], 1+is_odd(3))
2 # callable(2) is False
I would write it like this:
def countOddNumbers(numbers):
sum = 0
for num in numbers:
if num%2!=0:
sum += numbers.count(num)
return sum
not sure if i got your question , but as above something similar:
def countOddNumbers(numbers):
count=0
for i in numbers:
if i%2!=0:
count+=1
return count
Generator can give quick result in one line code:
sum((x%2 for x in nums))

Categories

Resources