Python list of object extraction into sub list - python

Say I have a class called 'points' with attributes 'x' and 'y'
and I create a list of points p = [p1,p2,p3,p4]
where p1.x = x1, py.y = y1 ...
How do I easily extract all the x and y values as a list?
e.g.
x = [x1,x2,x3,x4]
y = [y1,y2,y3,y4]
can this be done simply in one line of code in python?

You can do something like this:
p = [p1,p2,p3,p4]
x = [point.x for point in p]
y = [point.y for point in p]

x = [point.x for point in p]
y = [point.y for point in p]
could work but this will iterate the p twice, which is unnecessary ,You could try:
p = [p1, p2, p3, p4]
x, y = list(zip(*[(point.x, point.y) for point in p]))

Here you are
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
points = [Point(1,2), Point(3,4), Point(5,6), Point(7,8)]
x = [p.x for p in points]
y = [p.y for p in points]
print(x)
print(y)
Output :
[1, 3, 5, 7]
[2, 4, 6, 8]
Try it here

You could do it like this
x, y = [point.x for point in p],[point.y for point in p]

Related

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

Want to concatenate the random uniformly generated values

I have code as following and I want to write a function for it. output should be x as dataframe and y as series, even dataframe having x and y as columns is enough.
x = np.arange(0,50)
x = pd.DataFrame({'x':x})
# just random uniform distributions in differnt range
y1 = np.random.uniform(10,15,10)
y2 = np.random.uniform(20,25,10)
y3 = np.random.uniform(0,5,10)
y4 = np.random.uniform(30,32,10)
y5 = np.random.uniform(13,17,10)
y = np.concatenate((y1,y2,y3,y4,y5))
y = y[:,None]
I tried following but it doesn't return values from y1 to y5.
My code is :
x = np.arange(0,50)
x = pd.DataFrame({'x':x})
def colm(p,q):
s, t = p, q
a = ['y1', 'y2', 'y3', 'y4', 'y5']
for i in a:
i = np.random.uniform(s, t, 10)
s, t = s+10, t+10
return i
Try to modify the function like this:
def colm(p, q, chunk_len=10):
x = np.arange(0,5 * chunk_len)
x = pd.DataFrame({'x':x})
# just random uniform distributions in differnt range
ys = [np.random.uniform(p_, q_, chunk_len) for p_, q_ in zip(p, q)]
y = np.concatenate(ys)
return x, pd.Series(y)
You can now use it as
x, y = colm([10, 20, 0, 30, 13], [15, 25, 5, 13, 17])
I got it after some try what I was looking for:
x = np.arange(0,50)
x = pd.DataFrame({'x':x})
def colm(p,q):
s, t = p, q
z = []
a = ['y1', 'y2', 'y3', 'y4', 'y5']
for i in a:
i = np.random.uniform(s, t, 10)
s, t = s+10, t+10
z.append(i)
y = np.concatenate(z)
return pd.Series(y)
Thanks everyone for showing interest....!

Python 2.7 - Can't get full list/array from my for loop

I am working on a program that can convolve two lists and I need to do it from scratch. I have the correct output from my for loop, however I can't return it because the appended output will only save the last iteration of the for loop. I've tried enumerate, append, extend, and several others, I just don't know python enough to get a list or ideally an array of ints from my for loop.
import numpy as np
#def conv395(x,h):
#Function to convolve x input signal and h impulse response
h = [1,2,-1,1]
x = [1,1,2,1,2,2,1,1]
M = len(h)-1
L = len(x)
Ly = M+L
def ConV(x,h,n):
y = (h[m]*x[(n-1)-m])
return (y)
for n in range(0,Ly+1):
mx = n-L+1
if mx < 1:
n = n+1
#print("SPACE")
Y1 = 0
if n <= M+1:
Y = []
for m in range(n):
#print(n)
y = ConV(x,h,n)
Y1 = y + Y1
Y.append(Y1)
print Y,
OUTPUT
[1] [3] [3] [5]
HOWEVER
Y type=list size=1 Value=[5]
I need the Value to match the output in a list or array.
Any help would be greatly appreciated,thanks!
something like this maybe?
h = [1,2,-1,1]
x = [1,1,2,1,2,2,1,1]
M = len(h)-1
L = len(x)
Ly = M+L
LOL = []
def ConV(x,h,n):
y = (h[m]*x[(n-1)-m])
return (y)
for n in range(0,Ly+1):
mx = n-L+1
if mx < 1:
n = n+1
#print("SPACE")
Y1 = 0
if n <= M+1:
Y = []
for m in range(n):
#print(n)
y = ConV(x,h,n)
Y1 = y + Y1
Y.append(Y1)
LOL.append(Y)
print Y,
print LOL

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

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)

Select values in arrays

I have two arrays of the same length:
x = [2,3,6,100,2,3,5,8,100,100,5]
y = [2,3,4,5,5,5,2,1,0,2,4]
I selected the position where x==100 in this way:
How is possible to have the value of y where x==100? (that is y=5,0,2)?
I tried in this way:
x100=np.where(x==100)
y100=y[x100]
but it doesn't give me the values I want. How can I solve the problem?
Your code works fine when actually using numpy arrays. You can also write it more succinctly like so.
>>> import numpy as np
>>> x = np.array([2,3,6,100,2,3,5,8,100,100,5])
>>> y = np.array([2,3,4,5,5,5,2,1,0,2,4])
>>> y[x == 100]
array([5, 0, 2])
x and y should be numpy arrays:
x = np.array([2,3,6,100,2,3,5,8,100,100,5])
y = np.array([2,3,4,5,5,5,2,1,0,2,4])
Then your code should work as you expect.
What about
[b for (a,b) in zip(x,y) if a==100]
or
itertools.compress(y, [a==100 for a in x])
Iterate over both and check for 100:
x = [2,3,6,100,2,3,5,8,100,100,5]
y = [2,3,4,5,5,5,2,1,0,2,4]
for xi, yi in zip(x, y):
if xi == 100:
print(yi)
Prints:
5
0
2
Or as list comprehension:
>>> [yi for xi, yi in zip(x, y) if xi == 100]
[5, 0, 2]

Categories