Python-search function - python

I want to write a search function that takes in a value x and a sorted sequence and returns the position that the value should go to by iterating through the elements of the sequence starting from the first element. The position that x should go to in the list should be the first position such that it will be less than or equal to the next element in the list.
Example:>>> search(-5, (1, 5, 10))——0
>>> search(3, (1, 5, 10))——1

Building a list of every item would be a bit of a waste of resources if there were big gaps in the list, instead you can just iterate through each list item until the input is bigger than the value.
In terms of your code -
def search(input,inputList):
for i in range( len( inputList ) ):
if inputList[i]>input:
return i
return len( inputList )
print search(-5, (1, 5, 10))
#Result: 0
print search(3, (1, 5, 10))
#Result: 1
To insert it into the list, this would work, I split the list in 2 based on the index and add the value in the middle.
def insert(input,inputList):
index = search(input,inputList) #Get where the value should be inserted
newInput = [input]+list(inputList[index:]) #Add the end of the list to the input
if index:
newInput = list(inputList[:index])+newInput #Add the start of the list if the index isn't 0
return newInput
print insert(-5, (1, 5, 10))
#Result: (-5, 1, 5, 10)
print insert(3, (1, 5, 10))
#Result: (1, 3, 5, 10)

since someone has answered a similar question, I will just draw a rough skeleton of what u may want to do.
declare a list and populate it with your stuff;
mylist = [1, 2, 3, 5, 5, 6, 7]
then just make a function and iterate the list;
def my_func( x, mylist):
for i in mylist:
if((mylist[i] == x)|| (mylist[i] > x)):
return i
Given 3 in list (1, 2, 3, 4, 5), the function should return index 2.
Given 3 in list (1, 2, 4, 5, 6), it should still return 2
You may want to check my python code, because I have not checked this for errors, I am assuming you know some python and if you have the skeleton, you should crack it. And Oh, python cares about the tabbibg I did.

Related

How to store calculated values?

I have been trying to write code which gives the solution of the number of ways of reaching a sum, which is specified. This is very similar to the subset sums problem which I have found online (Finding all possible combinations of numbers to reach a given sum).
I modified slightly the code so that it reuses numbers multiple times.
object_list = [(2, 50), (3, 100), (5, 140)] # the first number in the tuple is my weight and the second is my cost
max_weight = 17
weight_values = [int(i[0]) for i in object_list]
cost_values = [int(i[1]) for i in object_list]
def subset_sum(objects, max_weight, weights=[]):
w = sum(weights)
if w == max_weight:
print("sum(%s)=%s" % (weights, max_weight))
if w >= max_weight:
return
for i in range(len(objects)):
o = objects[i]
subset_sum(objects, max_weight, weights + [o])
if __name__ == "__main__":
subset_sum(weight_values, max_weight)
print(subset_sum(weight_values, max_weight))
This gives the solution:
sum([2, 2, 2, 2, 2, 2, 2, 3])=17
sum([2, 2, 2, 2, 2, 2, 3, 2])=17
sum([2, 2, 2, 2, 2, 2, 5])=17
sum([2, 2, 2, 2, 2, 3, 2, 2])=17
...
So on so forth.
Unlike the original I am using a list of tuples and then taking the first value of the tuple to make a list. This is the same with the last value.
The part I am currently stuck on is how to store these values and reuse them in the next part of the code.I had a look at this post but I couldn't understand it (Python: How to store the result of an executed function and re-use later?).
So I want to store the part of the solution which stores [2, 2, 2, 2, 2, 2, 2, 3] from the solution sum([2, 2, 2, 2, 2, 2, 2, 3])=17. I want to do this for all solutions because in the next step i am going to replace the numbers with the next part of the tuple (so 2 will be replaced by 50 because the tuple that 2 is in is (2,50)). Then I am going to use this to print another sum value with the replaced numbers and print the highest value (probably going to sort the solutions from highest to lowest and print the first value in the list)
I tried using a dictionary to try and replace the values after the calculation but i couldn't manage to do it.
I tried:
dictionary = dict(zip(weight_values, cost_values))
Any help is appreciated. before anyone asks Ia have looked online for solutions and have no one else to ask help from, since the only person i know who has a background in coding is my brother who isn't at home

Number of distinct items between two consecutive uses of an item in realtime

I'm working on an problem that finds the distance- the number of distinct items between two consecutive uses of an item in realtime. The input is read from a large file (~10G), but for illustration I'll use a small list.
from collections import OrderedDict
unique_dist = OrderedDict()
input = [1, 4, 4, 2, 4, 1, 5, 2, 6, 2]
for item in input:
if item in unique_dist:
indx = unique_dist.keys().index(item) # find the index
unique_dist.pop(item) # pop the item
size = len(unique_dist) # find the size of the dictionary
unique_dist[item] = size - indx # update the distance value
else:
unique_dist[item] = -1 # -1 if it is new
print input
print unique_dist
As we see, for each item I first check if the item is already present in the dictionary, and if it is, I update the value of the distance or else I insert it at the end with the value -1. The problem is that this seems to be very inefficient as the size grows bigger. Memory isn't a problem, but the pop function seems to be. I say that because, just for the sake if I do:
for item in input:
unique_dist[item] = random.randint(1,99999)
the program runs really fast. My question is, is there any way I could make my program more efficient(fast)?
EDIT:
It seems that the actual culprit is indx = unique_dist.keys().index(item). When I replaced that with indx = 1. The program was orders of magnitude faster.
According to a simple analysis I did with the cProfile module, the most expensive operations by far are OrderedDict.__iter__() and OrderedDict.keys().
The following implementation is roughly 7 times as fast as yours (according to the limited testing I did).
It avoids the call to unique_dist.keys() by maintaining a list of items keys. I'm not entirely sure, but I think this also avoids the call to OrderedDict.__iter__().
It avoids the call to len(unique_dist) by incrementing the size variable whenever necessary. (I'm not sure how expensive of an operation len(OrderedDict) is, but whatever)
def distance(input):
dist= []
key_set= set()
keys= []
size= 0
for item in input:
if item in key_set:
index= keys.index(item)
del keys[index]
del dist[index]
keys.append(item)
dist.append(size-index-1)
else:
key_set.add(item)
keys.append(item)
dist.append(-1)
size+= 1
return OrderedDict(zip(keys, dist))
I modified #Rawing's answer to overcome the overhead caused by the lookup and insertion time taken by set data structure.
from random import randint
dist = {}
input = []
for x in xrange(1,10):
input.append(randint(1,5))
keys = []
size = 0
for item in input:
if item in dist:
index = keys.index(item)
del keys[index]
keys.append(item)
dist[item] = size-index-1
else:
keys.append(item)
dist[item] = -1
size += 1
print input
print dist
How about this:
from collections import OrderedDict
unique_dist = OrderedDict()
input = [1, 4, 4, 2, 4, 1, 5, 2, 6, 2]
for item in input:
if item in unique_dist:
indx = unique_dist.keys().index(item)
#unique_dist.pop(item) # dont't pop the item
size = len(unique_dist) # now the directory is one element to big
unique_dist[item] = size - indx - 1 # therefor decrement the value here
else:
unique_dist[item] = -1 # -1 if it is new
print input
print unique_dist
[1, 4, 4, 2, 4, 1, 5, 2, 6, 2]
OrderedDict([(1, 2), (4, 1), (2, 2), (5, -1), (6, -1)])
Beware that the entries in unique_dist are now ordered by there first occurrence of the item in the input; yours were ordered by there last occurrence:
[1, 4, 4, 2, 4, 1, 5, 2, 6, 2]
OrderedDict([(4, 1), (1, 2), (5, -1), (6, -1), (2, 1)])

issue with removing item from list in python

In the method below, I have assembled a list of tuples, while trying to ensure that none of the values are less than zero. The method below first takes a block and uses it to calculate the coordinates of neighboring blocks in increments of one and then proceeds to remove blocks that have either of their coordinates less than zero. My issue lies in the second stage as it does not remove two coordinates if I input a block with coordinates (0,0): (0,-1) and (-1,0).
The codes is as follows:
def get_block_neighbors(self, block):
neighbor_list = []
neighbor_list.append((block.x,block.y+1))
neighbor_list.append((block.x+1,block.y+1))
neighbor_list.append((block.x+1,block.y))
neighbor_list.append((block.x+1,block.y-1))
neighbor_list.append((block.x,block.y-1))
neighbor_list.append((block.x-1,block.y-1))
neighbor_list.append((block.x-1,block.y))
neighbor_list.append((block.x-1,block.y+1))
for item in neighbor_list: #each tuple item in the list
if item[0] < 0 or item[1] < 0:
print item
neighbor_list.remove(item)
print neighbor_list
get_block_neighbors(Block(Point(0,0),"green"))
for which I get the following output:
(1, -1)
(-1, -1)
(-1, 1)
[(0, 1), (1, 1), (1, 0), (0, -1), (-1, 0)]
Here, the first three lines are printouts of the tuples I would like to remove, while the last one is a list of the tuples that I have assembled. As you can see, the last two tuples have negative values for at least one of their coordinates. Ideally, I would want this:
(1, -1)
(-1, -1)
(-1, 1)
(0, -1)
(-1, 0)
[(0, 1), (1, 1), (1, 0)]
Curiously enough, when I remove/comment out the line neighbor_list.remove(item), I get a bit closer to where I need to be in one sense in that the method in its print-out includes the two tuples that I want removed. But of course, the one disadvantage of doing this is that I no longer remove any of the target tuples from this list.
Any help on this would be much appreciated and I really do hope that my oversight wasn't something super obvious. On a side note, I feel like there should be a way to assemble this list while being able to forego a removal stage, which is how I started coding this method before I just settled for the code above. Thanks!
The issue is that you're removing items from the list at the same time you're iterating over that list. List iteration happens by index (behind the scenes) so this doesn't work as you'd expect, as some values are skipped when their predecessors are removed.
To avoid this issue, you can iterate over a copy of the list, using a slice:
for item in neighbor_list[:]:
Or, better yet, use a list comprehension to build a new list instead of modifying the old one:
new_list = [(x, y) for x, y in neighbor_list if x >= 0 and y >= 0]
You shouldn't remove items from a list you're iterating over. Make a copy of the list first, and iterate over that instead.
The problem lies in the fact that you're removing elements of a list and at the same time you're iterating over it. It's simpler if you just create a new list with the elements removed:
[item for item in neighbor_list if item[0] >= 0 and item[1] >= 0]
Make a copy of the list first:
for item in neighbor_list[:]: #each tuple item in the list
if item[0] < 0 or item[1] < 0:
print item
neighbor_list.remove(item)
print neighbor_list
Much easier all around:
def get_block_neighbors(self, block):
neighbor_list = []
neighbor_list.append((block.x,block.y+1))
neighbor_list.append((block.x+1,block.y+1))
neighbor_list.append((block.x+1,block.y))
if block.y > 0:
neighbor_list.append((block.x+1,block.y-1))
neighbor_list.append((block.x,block.y-1))
if block.x > 0:
neighbor_list.append((block.x-1,block.y-1))
if block.x > 0:
neighbor_list.append((block.x-1,block.y))
neighbor_list.append((block.x-1,block.y+1))
return neighbor_list
Here is an example, showing some code that looks like it's trying to filter some numbers from a list
>>> L = range(10)
>>> for x in L:
... print x, L
... if x in (4,5,6,7):
... L.remove(x)
...
0 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
2 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
3 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
4 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
6 [0, 1, 2, 3, 5, 6, 7, 8, 9]
8 [0, 1, 2, 3, 5, 7, 8, 9]
9 [0, 1, 2, 3, 5, 7, 8, 9]
Removing items while iterating over the list is generally a bad idea.
Here is a simpler way to get the list of neighbors. It avoids the need for .remove altogether
def get_block_neighbors(self, block):
x = block.x
y = block.y
xrange = (-1, 0, 1)[x<1:]
yrange = (-1, 0, 1)[y<1:]
return [(x + dx,y + dy) for dx in xrange for dy in yrange if dx or dy]

Creating dynamic sublists from a list /sequence in python

Im trying to write a function that creates set of dynamic sublists each containing 5 elements from a list passed to it.Here's my attempt at the code
def sublists(seq):
i=0
x=[]
while i<len(seq)-1:
j=0
while j<5:
X.append(seq[i]) # How do I change X after it reaches size 5?
#return set of sublists
EDIT:
Sample input: [1,2,3,4,5,6,7,8,9,10]
Expected output: [[1,2,3,4,5],[6,7,8,9,10]]
Well, for starters, you'll need to (or at least should) have two lists, a temporary one and a permanent one that you return (Also you will need to increase j and i or, more practically, use a for loop, but I assume you just forgot to post that).
EDIT removed first code as the style given doesn't match easily with the expected results, see other two possibilities.
Or, more sensibly:
def sublists(seq):
x=[]
for i in range(0,len(seq),5):
x.append(seq[i:i+5])
return x
Or, more sensibly again, a simple list comprehension:
def sublists(seq):
return [seq[i:i+5] for i in range(0,len(seq),5)]
When given the list:
l = [1,2,3,4,5,6,7,8,9,10]
They will return
[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
Have you considered using itertools.combinations(...)?
For example:
>>> from itertools import combinations
>>> l = [1,2,3,4,5,6]
>>> list(combinations(l, 5))
[(1, 2, 3, 4, 5), (1, 2, 3, 4, 6), (1, 2, 3, 5, 6), (1, 2, 4, 5, 6), (1, 3, 4, 5, 6), (2, 3, 4, 5, 6)]
By "dynamic sublists", do you mean break up the list into groups of five elements? This is similar to your approach:
def sublists(lst, n):
ret = []
i = 0
while i < len(lst):
ret.append(seq[i:i+n])
i += n
return ret
Or, using iterators:
def sublists(seq, n):
it = iter(seq)
while True:
r = list(itertools.islice(it, 5))
if not r:
break
yield r
which will return an iterator of lists over list of length up to five. (If you took out the list call, weird things would happen if you didn't access the iterators in the same order.)

Python: Check an index against multiple other indexes

I am using Python and I would like to check the location of a value in a list of lists against other indexes.
Like if I had 1 at (1, 1) I would want to be able to check if 1 were at the other indexes so I could make something happen based on which index it matched.
For example:
list_of_lists = [
[4, 5, 6],
[7, 1, 8],
[6, 2, 9]
]
if 1 in row for row in list_of_lists:
if index of 1 is (0, 0), (0, 1), or (0, 2)
print ("It is in the First row!")
if index of 1 is (1, 0), (1, 1), or (1, 2)
print ("It is in the second row!")
If this worked correctly it should print: "It is in the second row!" Because the index of 1 matches with one of the indices in the third if statement. They may not necessarily be rows in some instances where I would be using this. So If you could provide a way that would not use the rows in your answer. Just a way to look at indexes and compare them. Obviously this is not the correct syntax. But how would I do that in Python? How would I get the index of 1 and compare it to other indexes in a list of lists?
Thanks!
trying this in a python file:
list_of_lists = [
[4, 5, 6],
[7, 0, 8],
[6, 2, 9]
]
def index_of(value, matrix):
for i, r in enumerate(matrix):
for j, c in enumerate(r):
if c == value:
# returns the first instance
return (i,j)
return None
if index_of(0, list_of_lists) == (1,1):
print "hey"
list_of_lists2 = [
[0, 5, 6],
[7, 0, 8],
[0, 2, 9]
]
def indexes_of(value, matrix):
return [(i,j) for i, r in enumerate(matrix) for j, c in enumerate(r) if c == value]
print indexes_of(0, list_of_lists2)
outputs
hey
[(0, 0), (1, 1), (2, 0)]
[EDIT] As requested:
First of all, what does enumerate do?
>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1))
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
source
As you can see, if you use enumerate, it will return both the index of the element AND the element. Therefore, while you're iterating over the returned list you can access them and do what you desire. That's what I'm doing here:
for i, r in enumerate(matrix)
In that case, i stands for the row index, and r stands for row itself. ok?
In the next line you do the same thing, but now you're enumerating the row itself, ok? And you're getting, now, the indexes of the values j and the values c that are stored in each row.
Finally, when you return (i,j), you're just returning a tuple that represents the values's matrix index.
Here's one way to do it:
>>> for lst in range(len(list_of_lists)):
... if 1 in list_of_lists[lst]:
... print "it's in list:", lst
...
it's in list: 1
>>>
remember the in operator tests whether a value appears in a list (or list like object).
Here's a second way using the index method (discussed in the comments);
>>> for lst in range(len(list_of_lists)):
... try:
... _ = list_of_lists[lst].index(1)
... print "1 is in list", lst
... except ValueError:
... continue
...
1 is in list 1
>>>
Something like this:
def lindex(list_of_lists, item):
for l in list_of_lists:
if item in l:
return list_of_lists.index(l)
listoflists = [[4, 5, 6], [7, 1, 8], [6, 2, 9]]
item = 1
print "it is in the %. row" % lindex(listoflists, item)
As for your attempt to shortcut with:
if 1 in row for row in list_of_lists:
The syntax is incorrect!
You can't avoid to look into every item of every row of the list - NO shortcut
For a halway valid compromise to 1. you could try something like:
rows = [i for i in listoflists if 1 in i]
This would at either give you an empty list, meaning there are no items with the value "1" or a list the rows containing "1"!
You could then print all row-indices containing 1 with:
for row in rows:
print "it is in the %. row" % listoflists.index(row)
for i,list in enumerate(list_of_lists, 1):
if 1 in list:
if i == 1:
"it is in the first list"
elif i == 2:
"it is in the second list"
...
This is a basic implementation. You would want to parameterize this but I'm not sure exactly what your inputs would be.

Categories