Python for loop on two dimensional index - python

This may be a simple task, but I am unsure of how to achieve this in Python.
I have a for loop executing on an index in Python. I have a unique value that is defined within each iteration that is cycled through the for loop.
I want to get the value of the NEXT or PREVIOUS for loop unique value. For example, I have:
counter = 0
for rect in rects:
randomnumber = random.randint(1,101)
if counter < len(rects)-1:
if rects[counter] - rects[counter+1]
pastrand = {get random value from PREVIOUS loop iteration}
randsubtract = randomnumber - pastrand
So how do I get the random number from the previous (or next) iteration to use in the CURRENT iteration in Python? For example:
randomnumber in rects[0]
randomnumber in rects[1]
How do I call specific values from iterations in for loops?

its late in the day, but this might do you..
counter = 0
random =[]
for rect in rects:
randomnumber = random.randint(1,101)
random.append(randomnumber)
if counter < len(rects)-1:
if rects[counter] - rects[counter+1]:
pastrand = random[-1]
randsubtract = randomnumber - pastrand

Option 1
Use enumerate. If you want the current and next, you'll need to iterate till len(rect) - 1. If you want the previous and current, you'll need to start iterating from 1.
for i, r in enumerate(rects[:-1]):
cur = r
next = rects[i + 1]
Or,
for i, r in enumerate(rects[1:]):
prev = rects[-1]
cur = r
Option 2
You can use zip to the same effect:
for cur, next in zip(rect, rect[1:]):
...

As written, you can save the value from the previous loop iteration before assigning a new one.
for ...:
pastrand = randomnumber
randomnumber = ...
Of course you will have to assign something to randomnumber before the loop starts so that the assignment works the very first time through.
An alternative would be to loop over pairs of random numbers rather than computing one random number per loop iteration. For this you can use the pairwise() tool whose implementation is given in the itertools documentation or e.g. in the more-itertools package. Looping over pairs of random numbers could be done like this:
for rand1, rand2 in pairwise(repeatfunc(random.randint, None, 1, 101)):
...
where I have used another itertool, repeatfunc(), to repeatedly call randint(). (You can do this without using repeatfunc() too.) At each iteration of this loop except the first, rand1 will be equal to rand2 from the previous iteration.
Now, you're going to want to pair each random number with a rectangle (assuming that's what is in rects), right? That you can do using zip(). Specifically, zip(random_numbers, rects) is an iterator over tuples of a random number and a rectangle. You could use it like so:
for randomnumber, rect in zip(random_numbers, rects):
...
but you're going to want to iterate over pairs, so you combine pairwise with that:
for r1, r2 in pairwise(zip(random_numbers, rects)):
rand1, rect1 = r1
rand2, rect2 = r2
...
Here random_numbers could be that thing I did earlier with repeatfunc(). This will associate one random number with each rectangle, and give you access to each set of two consecutive number/rectangle pairs.

Related

Is there a efficient way to iterate through?

I am using python for prototyping the following expression :
(n1^i1)*(n2^i2)*......*(n10^i10) = output/input_min (where I have to store i1,i2,i3,..)
I wrote something like this for only 3 elements.
passes = []
max_pass = 8
for i in range(0,max_pass):
for j in range(0,max_pass):
for k in range(0,max_pass):
temp = np.array([i, j, k])
comp = np.round(np.prod(basis**temp), 3)
ratio = np.round(self.output/self.input_min, 3)
if comp == ratio:
passes.append([i, j, k])
Considering I know n1,n2,...,n10 and the rigth hand ratio, Is there a way I can do it without writing 10 nested loops? (i1,i2,...i10 has to be integers)
Use an array of counters, all initialized to zero.
Form an endless loop where you increment the first counter. When the counter reaches the maximum value, reset it to zero and carry to the next counter. The next counter follows the same logics, and so on.
So the outer loop will include an inner carry propagation loop.
Processing terminates when the last counter carries.

Using python pick a random element from a list with replacement

I have a list of 40 elements. I am trying to estimate how many times I need to sample this list in order to reproduce all elements in that list. However, it is important that I replace the picked element. I.e. it is possible that I will pick the same element 20 times. So far I have the following
import random
l = range(0,40)
seen=[]
x=0
while len(seen)<len(l):
r = random.choice(l)
if r not in seen:
seen.append(r)
x=x+1
print x
However, this always returns that it took 40 times to accomplish what I want. However, this is because a single element is never selected twice.
Eventually I would run this function 1000 times to get a feel for how often I would have to sample.
as always, thanks
You need just adjust the indentation of x=x+1. Because right now you just increment if the value was not seen before.
If you will do that more often with a lot of items may use a set as your seen variable because access items is faster in avarage.
l = range(0, 40)
seen = set()
x = 0
while len(seen) < len(l):
r = random.choice(l)
if r not in seen:
seen.add(r)
x = x + 1
print x
Here is a similar method to do it. Initialize a set, which by definition may only contain unique elements (no duplicates). Then keep using random.choice() to choose an element from your list. You can compare your set to the original list, and until they are the same size, you don't have every element. Keep a counter to see how many random choices it takes.
import random
def sampleValues(l):
counter = 0
values = set()
while len(values) < len(l):
values.add(random.choice(l))
counter += 1
return counter
>>> l = list(range(40))
This number will vary, you could Monte Carlo to get some stats
>>> sampleValues(l)
180
>>> sampleValues(l)
334
>>> sampleValues(l)
179

Random sampling from a set of integers

I am working with python 3.2 and I spent a lot of time trouble shooting this, and I still can't seem to wrap my brain around it.
number = random.randint ( x0 ,xn )
I'm generating a random number. It's purpose is to make my code come at me differently everytime.
For example I have 10 variables of text that I have written. I have solved the problem of not having these variables appear in the same order at each program run.
The issue I have is that they now appear randomly everytime. It picks one out of 10 everytime, instead the first time 10 and next 9. I can't seem to find out how to exclude the previous ones.
thelist = [0]
while i < x
if number in thelist:
>>>repeat<<<
else:
thelist.append (number)
if ( number == x0 ):
>>>something<<<
elif ( number == x1 ):
>>>something<<<
This is what I would imagine the code would look like, everytime you loop one more number gets appended to the list, so that everytime it picks a number already in the list it repeats the loop again until it then has used all the numbers that random.randint can pull.
Here's a shuffle function:
import random
max = 15
x = list(range(max+1))
for i in range(max, 0, -1):
n = random.randint(0, i)
x[n], x[i] = x[i], x[n]
This starts with a sorted list of numbers [0, 1, ... max].
Then, it chooses a number from index 0 to index max, and swaps it with index max.
Then, it chooses a number from index 0 to index max-1, and swaps it with index max-1.
And so on, for max-2, max-3, ... 1
As yosukesabai rightly notes, this has the same effect as calling random.sample(range(max+1), max+1). This picks max + 1 unique random values from range(max+1). In other words, it just shuffles the order around. Docs: http://docs.python.org/2/library/random.html#random.sample
If you wanted something more along the lines of your proposed algorithm, you could do:
import random
max = 15
x = range(max+1)
l = []
for _ in range(max+1):
n = random.randint(0,max)
while n in l:
n = random.randint(0,max)
l.append(n)
From what I understand of your description and sample code, you want thelist to end up with every integer between x0 and xn in a random order. If so, you can achieve that very simply with random.shuffle(), which shuffles a list in place:
import random
x0 = 5
xn = 15
full_range = list(range(x0, xn))
print(full_range)
random.shuffle(full_range)
print(full_range)

Python: simplifying nested FOR loop?

I am wondering if there is a way to simplify the nested loop below. The difficulty is that the iterator for each loop depends on things from the previous loops. Here is the code:
# Find the number of combinations summing to 200 using the given list of coin
coin=[200,100,50,20,10,5,2,1]
total=[200,0,0,0,0,0,0,0]
# total[j] is the remaining sum after using the first (j-1) types of coin
# as specified by i below
count=0
# count the number of combinations
for i in range(int(total[0]/coin[0])+1):
total[1]=total[0]-i*coin[0]
for i in range(int(total[1]/coin[1])+1):
total[2]=total[1]-i*coin[1]
for i in range(int(total[2]/coin[2])+1):
total[3]=total[2]-i*coin[2]
for i in range(int(total[3]/coin[3])+1):
total[4]=total[3]-i*coin[3]
for i in range(int(total[4]/coin[4])+1):
total[5]=total[4]-i*coin[4]
for i in range(int(total[5]/coin[5])+1):
total[6]=total[5]-i*coin[5]
for i in range(int(total[6]/coin[6])+1):
total[7]=total[6]-i*coin[6]
count+=1
print count
I recommend looking at http://labix.org/python-constraint which is a Python constraint library. One of its example files is actually permutations of coinage to reach a specific amount, and it all handles it for you once you specify the rules.
You can get rid of all the int casting. An int/int is still an int in python ie integer division.
it looks like Recursion would clean this up nicly
count = 0
coin=[200,100,50,20,10,5,2,1]
total=[200,0,0,0,0,0,0,0]
def func(i):
global count,total,coin
for x in range(total[i-1]/coin[i-1]+1):
total[i]=total[i-1]-x*coin[i-1]
if (i == 7):
count += 1
else:
func(i+1)
func(1)
print count
combinations = set()
for i in range(len(coins)):
combinations = combinations | set(for x in itertools.combinations(coins, i) if sum(x) == 200)
print len(combinations)
It's a little slow, but it should work.

Generate 4000 unique pseudo-random cartesian coordinates FASTER?

The range for x and y is from 0 to 99.
I am currently doing it like this:
excludeFromTrainingSet = []
while len(excludeFromTrainingSet) < 4000:
tempX = random.randint(0, 99)
tempY = random.randint(0, 99)
if [tempX, tempY] not in excludeFromTrainingSet:
excludeFromTrainingSet.append([tempX, tempY])
But it takes ages and I really need to speed this up.
Any ideas?
Vincent Savard has an answer that's almost twice as fast as the first solution offered here.
Here's my take on it. It requires tuples instead of lists for hashability:
def method2(size):
ret = set()
while len(ret) < size:
ret.add((random.randint(0, 99), random.randint(0, 99)))
return ret
Just make sure that the limit is sane as other answerers have pointed out. For sane input, this is better algorithmically O(n) as opposed to O(n^2) because of the set instead of list. Also, python is much more efficient about loading locals than globals so always put this stuff in a function.
EDIT: Actually, I'm not sure that they're O(n) and O(n^2) respectively because of the probabilistic component but the estimations are correct if n is taken as the number of unique elements that they see. They'll both be slower as they approach the total number of available spaces. If you want an amount of points which approaches the total number available, then you might be better off using:
import random
import itertools
def method2(size, min_, max_):
range_ = range(min_, max_)
points = itertools.product(range_, range_)
return random.sample(list(points), size)
This will be a memory hog but is sure to be faster as the density of points increases because it avoids looking at the same point more than once. Another option worth profiling (probably better than last one) would be
def method3(size, min_, max_):
range_ = range(min_, max_)
points = list(itertools.product(range_, range_))
N = (max_ - min_)**2
L = N - size
i = 1
while i <= L:
del points[random.randint(0, N - i)]
i += 1
return points
My suggestion :
def method2(size):
randints = range(0, 100)
excludeFromTrainingSet = set()
while len(excludeFromTrainingSet) < size:
excludeFromTrainingSet.add((random.choice(randints), random.choice(randints)))
return excludeFromTrainingSet
Instead of generation 2 random numbers every time, you first generate the list of numbers from 0 to 99, then you choose 2 and appends to the list. As others pointed out, there are only 10 000 possibilities so you can't loop until you get 40 000, but you get the point.
I'm sure someone is going to come in here with a usage of numpy, but how about using a set and tuple?
E.g.:
excludeFromTrainingSet = set()
while len(excludeFromTrainingSet) < 40000:
temp = (random.randint(0, 99), random.randint(0, 99))
if temp not in excludeFromTrainingSet:
excludeFromTrainingSet.add(temp)
EDIT: Isn't this an infinite loop since there are only 100^2 = 10000 POSSIBLE results, and you're waiting until you get 40000?
Make a list of all possible (x,y) values:
allpairs = list((x,y) for x in xrange(99) for y in xrange(99))
# or with Py2.6 or later:
from itertools import product
allpairs = list(product(xrange(99),xrange(99)))
# or even taking DRY to the extreme
allpairs = list(product(*[xrange(99)]*2))
Shuffle the list:
from random import shuffle
shuffle(allpairs)
Read off the first 'n' values:
n = 4000
trainingset = allpairs[:n]
This runs pretty snappily on my laptop.
You could make a lookup table of random values... make a random index into that lookup table, and then step through it with a static increment counter...
Generating 40 thousand numbers inevitably will take a while. But you are performing an O(n) linear search on the excludeFromTrainingSet, which takes quite a while especially later in the process. Use a set instead. You could also consider generating a number of coordinate sets e.g. over night and pickle them, so you don't have to generate new data for each test run (dunno what you're doing, so this might or might not help). Using tuples, as someone noted, is not only the semantically correct choice, it might also help with performance (tuple creation is faster than list creation). Edit: Silly me, using tuples is required when using sets, since set members must be hashable and lists are unhashable.
But in your case, your loop isn't terminating because 0..99 is 100 numbers and two-tuples of them have only 100^2 = 10000 unique combinations. Fix that, then apply the above.
Taking Vince Savard's code:
>>> from random import choice
>>> def method2(size):
... randints = range(0, 100)
... excludeFromTrainingSet = set()
... while True:
... x = size - len(excludeFromTrainingSet)
... if not x:
... break
... else:
... excludeFromTrainingSet.add((choice(randints), choice(randints)) for _ in range(x))
... return excludeFromTrainingSet
...
>>> s = method2(4000)
>>> len(s)
4000
This is not a great algorithm because it has to deal with collisions, but the tuple-generation makes it tolerable. This runs in about a second on my laptop.
## for py 3.0+
## generate 4000 points in 2D
##
import random
maxn = 10000
goodguys = 0
excluded = [0 for excl in range(0, maxn)]
for ntimes in range(0, maxn):
alea = random.randint(0, maxn - 1)
excluded[alea] += 1
if(excluded[alea] > 1): continue
goodguys += 1
if goodguys > 4000: break
two_num = divmod(alea, 100) ## Unfold the 2 numbers
print(two_num)

Categories

Resources