numpy 3D indexing by list - python

Why do these different ways of indexing into X return different values?
print vertices[0]
print X[vertices[0]]
print X[tuple(vertices[0])]
print X[vertices[0][0]], X[vertices[0][1]], X[vertices[0][2]]
print [X[v] for v in vertices[0]]
And the output:
[(0, 2, 3), (0, 2, 4), (0, 3, 3)]
[-1. -0.42857143 0.14285714]
[-1. -0.42857143 0.14285714]
-0.428571428571 -0.428571428571 -0.142857142857
[-0.4285714285714286, -0.4285714285714286, -0.1428571428571429]
How can I use vertices[0] to get the output in the last line?

If you had used four vertices instead of three, writing
vertices = [[(0, 2, 3), (0, 2, 4), (0, 3, 3), (3,3,3)],]
followed by
print X[tuple(vertices[0])]
then the error message
IndexError: too many indices for array
would have shown that the right way to go is
print X[zip(*vertices[0])]
or definining the elements of vertices like
# rtices[0] = [(0, 2, 3), (0, 2, 4), (0, 3, 3), (3,3,3)]
# 4 different i's 4 j's 4 k's
vertices[0] = [(0,0,0,3), (2,2,3,3), (3,4,3,3)]

The thing is :
X[tuple(vertices[0])]
takes:
X[0][0][0],X[2][2][3],x[3][4][3]
while in:
X[[vertices[0][0]], X[vertices[0][1]], X[vertices[0][2]]]
vertices[0][0],[vertices[0][0],[vertices[0][0] are all same = 0, i.e. why different results than previous ones.

Related

Python making tuple of an array with a step 2

els = [1, 2, 3, 4, ]
print([(v, els[idx + 1]) for idx, v in enumerate(els[::2])])
Why does Python output [(1, 2), (3, 3)] instead of [(1, 2), (3, 4)]?
PS: I know I could do this: [(els[i], els[i + 1]) for i in range(0,len(els),2)] I'm not asking for a solution, I'm asking why is this?
why is this?
Take closer look at enumerate(els[::2]), consider following simple code
els = [1,2,3,4,5,6,7,8,9]
for elem in enumerate(els[::2]):
print(elem)
gives output
(0, 1)
(1, 3)
(2, 5)
(3, 7)
(4, 9)
Observe that numbering was applied after slicing but you are using index to access element of list before slicing and they are not in unison.

Display the names of each element in my list

UPDATE: Okay, I did a complete overhaul of this question. Same question, but now I implemented my own code.
To start this off, all a, b, c, d and e are columns within a data frame that I will be doing a permutation of only 3 combinations at a time like the following:
data = list(iter.permutations([a, b, c, d, e], 3)
Then, I do the following to use a specific row within my data frame to find a single point on my graph:
specData = list(iter.permutations(spec[a.name], spec[b.name], spec[c.name],
spec[d.name], spec[e.name], 3)
Then, I will loop to display every possible graph due to my permutation. All of this works in my code and displays them correctly. I left out the non-needed part which is creating the format of the graph since none of that actually matters in this question:
for i in range(len(data)):
plt.scatter(data[i][0] - data[i][1], data[i][0] - data[I][2], edgecolors=‘b’)
plt.scatter(specData[i][0] - specData[i][1], specData[i][0] - specData[i][2],
edgecolors=‘r’)
On my previous graphs using data frames, I was able to display the names of the labels by creating them like this and graphing them one-by-one:
plt.xlabel(a.name + ‘-‘ + b.name)
plt.ylabel(a.name + ‘-‘ + c.name)
The output from the labels above would look like this on the graph's x and y labels:
a-b
a-c
Now, I'm not sure how to display names with a list like I do with a data frame, especially when its going to be "random" each time I loop a new tuple within a list, so I can't just hard-code it to be a, b, c, d, or e since I have no idea. I was assuming to use a dictionary, but I’m not sure how I would go about it.
You can zip a named_list with your data and assign each element of data a name.
Code:
from string import ascii_lowercase
def do():
data = [[(0, 1, 2), (3, 4, 5), (6, 7, 8)],
[(0, 1, 2), (6, 7, 8), (3, 4, 5)],
[(3, 4, 5), (6, 7, 8), (0, 1, 2)]]
featured_list = list(map(lambda x: list(zip(ascii_lowercase, x)), data))
for items in featured_list:
for item in items:
print(f"{item[0]}: {item[1]}")
if __name__ == '__main__':
do()
Output:
a: (0, 1, 2)
b: (3, 4, 5)
c: (6, 7, 8)
a: (0, 1, 2)
b: (6, 7, 8)
c: (3, 4, 5)
a: (3, 4, 5)
b: (6, 7, 8)
c: (0, 1, 2)
Try this:
from string import ascii_lowercase
alphabet=0
for i in data:
for j in i:
print(ascii_lowercase[alphabet] + " : " + str(j))
alphabet += 1
I have some more questions though like what if your list's length exceeds alphabet size? Also, this answer is valid if you just want to print and not store.
Not sure if that's what you are looking for but you can match each tuple as a key and add values as you like. i.e.:
data = [[(0, 1, 2), (3, 4, 5), (6, 7, 8)],
[(0, 1, 2), (6, 7, 8), (3, 4, 5)],
[(3, 4, 5), (6, 7, 8), (0, 1, 2)]]
dict1 = {(0, 1, 2): 'a', (3, 4, 5): 'b', (6, 7, 8): 'c'}
for row in data:
print(', '.join(['%s:%s' % (dict1[elem], elem) for elem in row if elem in dict1]))
You can use the function chain.from_iterable() to iterate over each element in each sublist:
from itertools import chain
from string import ascii_lowercase
c = chain.from_iterable(data)
for i, j in zip(ascii_lowercase, c):
print(i, j, sep = ' : ')
If you want to build a dictionary you can use the functions dict() and zip():
c = chain.from_iterable(data)
dct = dict(zip(ascii_lowercase, c))

create list of adjacent elements of another list in Python

I am looking to take as input a list and then create another list which contains tuples (or sub-lists) of adjacent elements from the original list, wrapping around for the beginning and ending elements. The input/output would look like this:
l_in = [0, 1, 2, 3]
l_out = [(3, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, 0)]
My question is closely related to another titled getting successive adjacent elements of a list, but this other question does not take into account wrapping around for the end elements and only handles pairs of elements rather than triplets.
I have a somewhat longer approach to do this involving rotating deques and zipping them together:
from collections import deque
l_in = [0, 1, 2, 3]
deq = deque(l_in)
deq.rotate(1)
deq_prev = deque(deq)
deq.rotate(-2)
deq_next = deque(deq)
deq.rotate(1)
l_out = list(zip(deq_prev, deq, deq_next))
# l_out is [(3, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, 0)]
However, I feel like there is probably a more elegant (and/or efficient) way to do this using other built-in Python functionality. If, for instance, the rotate() function of deque returned the rotated list instead of modifying it in place, this could be a one- or two-liner (though this approach of zipping together rotated lists is perhaps not the most efficient). How can I accomplish this more elegantly and/or efficiently?
One approach may be to use itertools combined with more_itertools.windowed:
import itertools as it
import more_itertools as mit
l_in = [0, 1, 2, 3]
n = len(l_in)
list(it.islice(mit.windowed(it.cycle(l_in), 3), n-1, 2*n-1))
# [(3, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, 0)]
Here we generated an infinite cycle of sliding windows and sliced the desired subset.
FWIW, here is an abstraction of the latter code for a general, flexible solution given any iterable input e.g. range(5), "abcde", iter([0, 1, 2, 3]), etc.:
def get_windows(iterable, size=3, offset=-1):
"""Return an iterable of windows including an optional offset."""
it1, it2 = it.tee(iterable)
n = mit.ilen(it1)
return it.islice(mit.windowed(it.cycle(it2), size), n+offset, 2*n+offset)
list(get_windows(l_in))
# [(3, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, 0)]
list(get_windows("abc", size=2))
# [('c', 'a'), ('a', 'b'), ('b', 'c')]
list(get_windows(range(5), size=2, offset=-2))
# [(3, 4), (4, 0), (0, 1), (1, 2), (2, 3)]
Note: more-itertools is a separate library, easily installed via:
> pip install more_itertools
This can be done with slices:
l_in = [0, 1, 2, 3]
l_in = [l_in[-1]] + l_in + [l_in[0]]
l_out = [l_in[i:i+3] for i in range(len(l_in)-2)]
Well, or such a perversion:
div = len(l_in)
n = 3
l_out = [l_in[i % div: i % div + 3]
if len(l_in[i % div: i % div + 3]) == 3
else l_in[i % div: i % div + 3] + l_in[:3 - len(l_in[i % div: i % div + 3])]
for i in range(3, len(l_in) + 3 * n + 2)]
You can specify the number of iterations.
Well I figured out a better solution as I was writing the question, but I already went through the work of writing it, so here goes. This solution is at least much more concise:
l_out = list(zip(l_in[-1:] + l_in[:-1], l_in, l_in[1:] + l_in[:1]))
See this post for different answers on how to rotate lists in Python.
The one-line solution above should be at least as efficient as the solution in the question (based on my understanding) since the slicing should not be more expensive than the rotating and copying of the deques (see https://wiki.python.org/moin/TimeComplexity).
Other answers with more efficient (or elegant) solutions are still welcome though.
as you found there is a list rotation slicing based idiom lst[i:] + lst[:i]
using it inside a comprehension taking a variable n for the number of adjacent elements wanted is more general [lst[i:] + lst[:i] for i in range(n)]
so everything can be parameterized, the number of adjacent elements n in the cyclic rotation and the 'phase' p, the starting point if not the 'natural' 0 base index, although the default p=-1 is set to -1 to fit the apparant desired output
tst = list(range(4))
def rot(lst, n, p=-1):
return list(zip(*([lst[i+p:] + lst[:i+p] for i in range(n)])))
rot(tst, 3)
Out[2]: [(3, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, 0)]
showing the shortend code as per the comment

manipulating the output of itertools.permutations in python

I want to take a list, for instance List = [1,2,2], and generate its permutations. I can do this with:
NewList = [list(itertools.permutations(List))]
and the output is:
[[(1, 2, 2), (1, 2, 2), (2, 1, 2), (2, 2, 1), (2, 1, 2), (2, 2, 1)]]
The Problem: itertools.permutations returns a list of length 1 whose only entry is the list of all permutations of List. That is:
NewList[0] == [(1,2,2),(1,2,2),(2,1,2),(2,2,1),(2,1,2),(2,2,1)]
and
NewList[1] does not exist.
I want the output to be a list where each entry is one of the permutations. That is
NewList[0] == (1,2,2)
NewList[1] == (1,2,2)
NewList[2] == (2,1,2)
...
NewList[5] == (2,2,1)
The Question: Is there a command that will produce the permutations of List in this way? Failing that, is there a way to access the 'individual elements' of [list(itertools.permutations(List))] so I can do things with them?
>>> from itertools import permutations
>>> list(permutations([1,2,2]))
[(1, 2, 2), (1, 2, 2), (2, 1, 2), (2, 2, 1), (2, 1, 2), (2, 2, 1)]
You don't need to put it in a list again. i.e Don't do [list(permutations(...))] (By doing [] you are making a nested list and hence are unable to access the elements using testList[index], though you could do testList[0][index] but it would be better to just keep it as a list of tuples.)
>>> newList = list(permutations([1, 2, 2]))
>>> newList[0]
(1, 2, 2)
>>> newList[3]
(2, 2, 1)
Now you can access the elements by using their indices.
Why can't you do this:
NewList = [list(itertools.permutations(List))][0]
or even just this:
NewList = list(itertools.permutations(List))
By doing [ list(itertools.permutations(List)) ], you put the list of permutations (the one that you want) inside of another list. So the fix would be to remove the outer []'s

Generating all possible combinations of a list, "itertools.combinations" misses some results

Given a list of items in Python, how can I get all the possible combinations of the items?
There are several similar questions on this site, that suggest using itertools.combinations, but that returns only a subset of what I need:
stuff = [1, 2, 3]
for L in range(0, len(stuff)+1):
for subset in itertools.combinations(stuff, L):
print(subset)
()
(1,)
(2,)
(3,)
(1, 2)
(1, 3)
(2, 3)
(1, 2, 3)
As you see, it returns only items in a strict order, not returning (2, 1), (3, 2), (3, 1), (2, 1, 3), (3, 1, 2), (2, 3, 1), and (3, 2, 1). Is there some workaround for that? I can't seem to come up with anything.
Use itertools.permutations:
>>> import itertools
>>> stuff = [1, 2, 3]
>>> for L in range(0, len(stuff)+1):
for subset in itertools.permutations(stuff, L):
print(subset)
...
()
(1,)
(2,)
(3,)
(1, 2)
(1, 3)
(2, 1)
(2, 3)
(3, 1)
....
Help on itertools.permutations:
permutations(iterable[, r]) --> permutations object
Return successive r-length permutations of elements in the iterable.
permutations(range(3), 2) --> (0,1), (0,2), (1,0), (1,2), (2,0), (2,1)
You can generate all the combinations of a list in python using this simple code
import itertools
a = [1,2,3,4]
for i in xrange(1,len(a)+1):
print list(itertools.combinations(a,i))
Result:
[(1,), (2,), (3,), (4,)]
[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
[(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]
[(1, 2, 3, 4)]
Are you looking for itertools.permutations instead?
From help(itertools.permutations),
Help on class permutations in module itertools:
class permutations(__builtin__.object)
| permutations(iterable[, r]) --> permutations object
|
| Return successive r-length permutations of elements in the iterable.
|
| permutations(range(3), 2) --> (0,1), (0,2), (1,0), (1,2), (2,0), (2,1)
Sample Code :
>>> from itertools import permutations
>>> stuff = [1, 2, 3]
>>> for i in range(0, len(stuff)+1):
for subset in permutations(stuff, i):
print(subset)
()
(1,)
(2,)
(3,)
(1, 2)
(1, 3)
(2, 1)
(2, 3)
(3, 1)
(3, 2)
(1, 2, 3)
(1, 3, 2)
(2, 1, 3)
(2, 3, 1)
(3, 1, 2)
(3, 2, 1)
From Wikipedia, the difference between permutations and combinations :
Permutation :
Informally, a permutation of a set of objects is an arrangement of those objects into a particular order. For example, there are six permutations of the set {1,2,3}, namely (1,2,3), (1,3,2), (2,1,3), (2,3,1), (3,1,2), and (3,2,1).
Combination :
In mathematics a combination is a way of selecting several things out of a larger group, where (unlike permutations) order does not matter.
itertools.permutations is going to be what you want. By mathematical definition, order does not matter for combinations, meaning (1,2) is considered identical to (2,1). Whereas with permutations, each distinct ordering counts as a unique permutation, so (1,2) and (2,1) are completely different.
Here is a solution without itertools
First lets define a translation between an indicator vector of 0 and 1s and a sub-list (1 if the item is in the sublist)
def indicators2sublist(indicators,arr):
return [item for item,indicator in zip(arr,indicators) if int(indicator)==1]
Next, Well define a mapping from a number between 0 and 2^n-1 to the its binary vector representation (using string's format function) :
def bin(n,sz):
return ('{d:0'+str(sz)+'b}').format(d=n)
All we have left to do, is to iterate all the possible numbers, and call indicators2sublist
def all_sublists(arr):
sz=len(arr)
for n in xrange(0,2**sz):
b=bin(n,sz)
yield indicators2sublist(b,arr)
I assume you want all possible combinations as 'sets' of values. Here is a piece of code that I wrote that might help give you an idea:
def getAllCombinations(object_list):
uniq_objs = set(object_list)
combinations = []
for obj in uniq_objs:
for i in range(0,len(combinations)):
combinations.append(combinations[i].union([obj]))
combinations.append(set([obj]))
return combinations
Here is a sample:
combinations = getAllCombinations([20,10,30])
combinations.sort(key = lambda s: len(s))
print combinations
... [set([10]), set([20]), set([30]), set([10, 20]), set([10, 30]), set([20, 30]), set([10, 20, 30])]
I think this has n! time complexity, so be careful. This works but may not be most efficient
just thought i'd put this out there since i couldn't fine EVERY possible outcome and keeping in mind i only have the rawest most basic of knowledge when it comes to python and there's probably a much more elegant solution...(also excuse the poor variable names
testing = [1, 2, 3]
testing2= [0]
n = -1
def testingSomethingElse(number):
try:
testing2[0:len(testing2)] == testing[0]
n = -1
testing2[number] += 1
except IndexError:
testing2.append(testing[0])
while True:
n += 1
testing2[0] = testing[n]
print(testing2)
if testing2[0] == testing[-1]:
try:
n = -1
testing2[1] += 1
except IndexError:
testing2.append(testing[0])
for i in range(len(testing2)):
if testing2[i] == 4:
testingSomethingElse(i+1)
testing2[i] = testing[0]
i got away with == 4 because i'm working with integers but you may have to modify that accordingly...

Categories

Resources