"Properly" organise (spread out) x and y data - python

Not really sure how to word this question, so I will give an example of what I want.
I have two variables xsteps and ysteps.
If xsteps is 4 and ysteps is 2, then I would like a variable result to be "x, x, y, x, x, y"
If xsteps is 10 and ysteps is 5, then I would like result to be
"x, x, y, x, x, y, x, x, y, x, x, y, x, x, y"
If xsteps is 15 and ysteps is 5 then I would like result to be "x, x, x, y, x, x, x, y, x, x, x, y, x, x, x, y, x, x, x, y"
If xsteps is 1 and ysteps is 6, I would like result to be "x, y, y, y, y, y, y"
If xsteps is 4 and ysteps is 4, I would like result to be "x, y, x, y, x, y, x, y"
If xsteps is 10 and ysteps is 4, I would like result to be "x, x, y, x, x, y, x, x, y, x, x, y, x, x"
Xsteps and ysteps are not always easily divisible. If they do not divide, then I would just like them to be kind of separated out. It does not need to be perfect, just so it spreads them out reasonable well.
Really, I need the xsteps and ysteps variables organised into one variable that spreads them out.

You can try something like this:
from __future__ import division
def spreadout(X, Y):
ratio = len(X) / len(Y)
result = []
while X or Y:
if not Y or len(X)/len(Y) >= ratio:
result.append(X.pop())
else:
result.append(Y.pop())
return result
The idea behind the algorithm is to determine the ratio of the X andY lists and to alternately pop elements from either of the lists to keep the ratio in the result list similar.
This implementaiton works with lists of arbitrary elements and will return the result as a list. If you want just your x,y string, the code can be simplified and optimized some, e.g. using len this often would be wasteful is you have very long lists of xs and ys. Or you can just write a wrapper for that:
def xy_wrapper(x, y):
return ",".join(spreadout(['x'] * x, ['y'] * y))
Example Output:
>>> spreadout(range(6), list("ABC"))
[5, 'C', 4, 3, 'B', 2, 1, 'A', 0]
>>> xy_wrapper(5, 17)
'x,y,y,y,y,x,y,y,y,x,y,y,y,y,x,y,y,y,x,y,y,y'

def spread_generator(xsteps, ysteps):
ratio = xsteps / ysteps
while xsteps > 0 or ysteps > 0:
if xsteps > ratio * ysteps:
yield "x"
xsteps -= 1
else:
yield "y"
ysteps -= 1
xsteps = 7
ysteps = 3
result = [x for x in spread_generator(xsteps, ysteps)]
# Next line will make result variable hold desired value
result.reverse()
print result
# ['x', 'x', 'y', 'x', 'x', 'y', 'x', 'x', 'y', 'x']
# And if you want string
result_as_str = ",".join(result)
print result_as_str
# x,x,y,x,x,y,x,x,y,x
The crucial value is the ratio between x and y steps.
The list is reversed in the beginning, so we reverse it.
Remember that list.reverse() modifies the list in place and returns None.

Looks like someone beat me to the punch with a much nicer response, but I've written it now!
This would do close to what you want, but your example for (10, 4) doesn't work the way you have specified it.
def xy_spread(xsteps, ysteps):
out = []
if xsteps == 0:
out = ['y'] * ysteps
else:
y_per_x = float(ysteps) / float(xsteps)
y_budget = 0.0
for _ in xrange(xsteps):
out.append('x')
y_budget += y_per_x
while y_budget >= 1:
y_budget -= 1
out.append('y')
return ','.join(out)

Not necessarily pretty, but functional.
Basically it seems you want to split the xsteps into chunks, and intersperse a "y" between the chunks until either the x's or y's run out.
def get_chunks(mylist, n):
"""
Adapted from:
http://www.how2code.co.uk/2013/04/how-to-split-a-list-into-chunks-in-python/
"""
if n == 0:
return mylist
else:
return [mylist[x:x+n] for x in range(0, len(mylist), n)]
def combine(xs=0, ys=0):
"""
>>> combine(xs=4, ys=2)
x,x,y,x,x,y
>>> combine(xs=10, ys=5)
x,x,y,x,x,y,x,x,y,x,x,y,x,x,y
>>> combine(xs=15, ys=5)
x,x,x,y,x,x,x,y,x,x,x,y,x,x,x,y,x,x,x,y
>>> combine(xs=1, ys=6)
x,y,y,y,y,y,y
>>> combine(xs=4, ys=4)
x,y,x,y,x,y,x,y
>>> combine(xs=10, ys=4)
x,x,y,x,x,y,x,x,y,x,x,y,x,x
"""
output = list()
x = ['x'] * xs
y = ['y'] * ys
step = xs // ys
xchunks = get_chunks(x, step)
while xchunks or y:
if xchunks:
output += xchunks.pop()
if y:
output += y.pop()
print ','.join(output)

Related

Think Python exercise 6.1

This is an exercise 6.1 in the book "Think Python". The question is to find the print result.
This is what I can get so far.
x = 1, y = 2
bring to a(x, y), return 4
b(z), return z**2 + z
I couldn't find the valve z from c(x, y, z) function.
def b(z):
prod = a(z, z)
print(z, prod)
return prod
def a(x, y):
x = x + 1
return x * y
def c(x, y, z):
total = x + y + z
square = b(total)**2
return square
x = 1
y = x + 1
print(c(x, y+3, x+y))
The x and y in def a(x, y): are not the same x and y defined elsewhere in the script. It might as well say def a(j, k):. When you see prod = a(z, z), you need to know what the value of z is, and then go to the definition of def a(j, k): and think j = z and k = z.
If we just tell you what the output is, then you wouldn't learn to "Think Python"

Count collisions in n-Queens problem in Python

I started working on python for AI and I'm having some problems:
I have an n- Queens problem here is a detailed explanation of the problem
The fitness function receives a an array of the form:
decoded = [3, 1, 2, 5 ... n]
where the element corresponds to the X coordinate and the index corresponds to the Y coordinate
i.e. taking the coordinates from the example above:
# [X, Y]
pairCoords = [[3,0], [1, 1], [2, 2], [5, 1], ... [n, z]]
so I have the fitness function which recieves a similar array to the first example.
var record starts with the max number of collisions n(n-1)* and decreases with each collision found
def fitness(self, decodedGenes):
record = self.numeroN * (self.numeroN-1)
for y in range(len(decodedGenes)):
if self.positionIsAtacking(decodedGenes, decodedGenes[y], y):
record = record - 1
return record
so a best case world return n(n-1)* and a worst case would return 0
the auxiliar function it calls checks a given X and Y coordinates and returns if there is a collision but it's not working
def positionIsAtacking(self, coords, X, Y):
for i in range(len(coords)):
# Check Y
if (coords[i] == Y):
return True
# Check Diagonals
if (coords[i] - Y == i - X):
return True
if (coords[i] - Y == X - i):
return True
return False
I have tried changing the parameters but I do not know where to search anymore I think the second function doesn`t work or maybe y changed x and y
def fitness(self, cromosoma):
record = self.numeroN * (self.numeroN - 1)
for row in range(len(board)):
decodedGenes.append(self.decodeGene(board[row]))
for y in range(len(decodedGenes)):
x = decodedGenes[y]
record = record - self.collisions(decodedGenes, x, y)
return record
def collisions(self, coords, X, Y):
board = []
r = 0
for i in range(len(coords)):
board.append([0] * self.numeroN)
for y in range(len(coords)):
board[y][coords[y]] = 1
for y in range(len(board)):
for x in range(len(board)):
# if has Queen and is not the same
if board[y][x] == 1 and y != Y:
# check x
if x == X:
r = r + 1
# check Diagonals
if self.crash_diagonal(x, y, X, Y):
r = r + 1
return r
def crash_diagonal(self, x1, y1, x2, y2):
dx = abs(x1 - x2)
dy = abs(y1 - y2)
return dx == dy

Defining list from a function with multiple arguments

I have the following function:
def func(x, y, z):
d = -5.9
T = 230.0
f = x - y * T + z + d
return f
From this, I want to make a single list of f-values extracted from func(x, y, z). The values x, y, and z are three different lists of values.
My question is, how do I make the list of f-values? I have tried the following, but it did not work properly:
f_list = [func(x, y, z) for x in x_list for y in y_list for z in z_list]
I think you want to use zip:
f_list = [func(*vals) for vals in zip(x_list, y_list, z_list)]
or for clearance:
f_list = [func(x, y, z) for x, y, z in zip(x_list, y_list, z_list)]
You can also use itertools.starmap:
import itertools
f_list = list(itertools.starmap(func, zip(x_list, y_list, z_list)))

A bijective function from N*N*N to N

Can anyone help me in finding a bijective mathematical function from N * N * N → N that takes three parameters x, y, and z and returns a number n?
I would like to know the function f and its inverse f' in a way that if I have n I will be able to determine x, y, z by applying f'(n).
Defining f as a composition of a simpler function g
Suppose g is a bijection from N × N to N and let g-1 be its inverse. Then we can define f in terms of g as follows.
f(x, y, z) = g(g(x, y), z) = n
f-1(n) = (x, y, z) where g-1(n) = (w, z) and g-1(w) = (x, y)
Defining g as a bijection from N × N to N
We now have the much simpler problem of defining g.
g(x, y) = (x + y)(x + y + 1) / 2 + y = n
g-1(n) = (x, y) where m = ⌊(2n)1/2⌋ and exactly one of the following two conditions hold.
x + y = m and y = n - m(m + 1) / 2
x + y = m - 1 and y = n - m(m - 1) / 2
Python implementation
def f(x, y, z):
return g(g(x, y), z)
def f_inv(n):
w, z = g_inv(n)
x, y = g_inv(w)
return (x, y, z)
def g(x, y):
return (x + y) * (x + y + 1) / 2 + y
def g_inv(n):
m = math.floor(math.sqrt(2 * n))
while True:
y = n - m * (m + 1) / 2
if y >= 0:
break
m -= 1
x = m - y
return x, y
your function is not surjective, let p is a prime number, we can't find any x,y,z in N such that p=2^x3^y5^z...
F(x,y,z) = 2^x*3^y*5^z
In fact you can choose any distinct set of prime numbers. And inverse is simply by factorizing to corresponding prime factors.

How do I turn a string of digits into a list of one-digit integers?

str(reduce(lambda x, y: x * y, range(1, 11))) -> this returns 10! or '3628800'
Without creating a for loop, how can I map this function to another function as a list of one-digit integers: e.g. reduce(lambda x, y: x+ y, [3, 6, 2, 8, 8, 0, 0])
Clarification:
reduce(lambda x, y: x + y, [str(reduce(lambda x, y: x * y, range(1, 11)))])
How do I turn everything inside the [ ] into a list of one-digit integers so that the first function can evaluate it? Of course I need to transform it inside the [ ].
I think you're simply looking for map(int, s) where s is the string you want to get integer digits from. For example:
>>> import math
>>> math.factorial(10)
3628800
>>> str(math.factorial(10))
'3628800'
>>> map(int,str(math.factorial(10)))
[3, 6, 2, 8, 8, 0, 0]
>>> sum(map(int,str(math.factorial(10))))
27
You can use a list comprehension:
[int(x) for x in str(reduce(lambda x, y: x * y, range(1, 11)))]
The final product:
reduce(lambda x, y: x + y, [int(x) for x in str(reduce(lambda x, y: x * y, range(1, 11)))])

Categories