Permutations excluding inverses [duplicate] - python

This question already has answers here:
How to generate permutations of a list without "reverse duplicates" in Python using generators
(10 answers)
Closed 5 years ago.
I need to get permutations, excluding mirrored sequences, i.e. (1, 0, 4) should be included, but (4, 0, 1) should be excluded after.
I've came up with the following function but is wondering whether there is simpler solution.
The function skips inverses basing on the fact their last element is the same as the first element of the corresponding sequence, which is already processed given lexicographical order.
def permutations_no_inverse(iterable):
"""Return the half of permutations, treating mirrored sequences as the same,
e.g. (0, 1, 2) and (2, 1, 0) are the same.
Assume itertools.permutations returns tuples
"""
all_perm = it.permutations(iterable)
cur_start = None
starts_processed = set()
for perm in all_perm:
new_start = perm[0]
if new_start != cur_start:
if cur_start != None:
starts_processed.add(cur_start)
cur_start = new_start
if perm[-1] in starts_processed:
continue
else:
yield perm

Assuming the entries in iterable are unique and orderable, I would simply compare any two elements of the permutation (e.g. the first and last one), and only include those permutations where the first element is less or equal than the last element. This way, you don't need to store what you have already seen, and you don't care in what order itertools.permutations() returns the permutations.
Example code:
def permutations_no_inverse(iterable):
for p in itertools.permutations(iterable):
if p[0] <= p[-1]:
yield p

Your question has explicited stated ...wondering whether there is simpler solution, i think the below one is simple enough:
def permutations_no_inverse(iterable):
found_items = []
for p in it.permutations(iterable):
if p not in found_items:
found_items.extend([p, p[::-1]])
else:
yield p

Based on the fact that python delays the reversed tuple-orderings all for the latest columns, we could envisage the permutations set as a uniform matrix, then divide it diagonally, to get the unmirrored part of the matrix.
k=[1, 2, 3,4]
l=itertools.permutations(k)
a=list(l)
b=np.array(a).reshape((len(k),len(a)/len(k),len(k)))
neat_list=np.flipud(b)[np.tril_indices(len(k))]
This should be effective with all array lengths I guess ....
With k=[1,2,3,4,5,6]
This prints
array([
[6, 1, 2, 3, 4, 5],
[5, 1, 2, 3, 4, 6],
[5, 1, 2, 3, 6, 4],
[4, 1, 2, 3, 5, 6],
[4, 1, 2, 3, 6, 5],
[4, 1, 2, 5, 3, 6],
[3, 1, 2, 4, 5, 6],
[3, 1, 2, 4, 6, 5],
[3, 1, 2, 5, 4, 6],
[3, 1, 2, 5, 6, 4],
[2, 1, 3, 4, 5, 6],
[2, 1, 3, 4, 6, 5],
[2, 1, 3, 5, 4, 6],
[2, 1, 3, 5, 6, 4],
[2, 1, 3, 6, 4, 5],
[1, 2, 3, 4, 5, 6],
[1, 2, 3, 4, 6, 5],
[1, 2, 3, 5, 4, 6],
[1, 2, 3, 5, 6, 4],
[1, 2, 3, 6, 4, 5],
[1, 2, 3, 6, 5, 4]])
I tried :
test=[list(g) for g in neat_list]
any([(u[::-1] in test) for u in test])
And this outputs false which means no occurence of reversed arrays there.

Related

Convert lists into higher dimension so that elements can be reached by following

I have a matrix that I want to convert to 3D so that I can be able to print the element of list[i][j][k]
a = [[[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 2, 3, 4,5], [3, 2, 3, 4, 3, 4], [4, 3, 4, 5, 4, 3], [5, 4, 5, 6, 5, 4]]]
print(a[5][5][0]) # I want to be able to print in 3D`
I get right output if I do a[5][5] but wrong when I add the [0]. Is there anyway of converting my matrix such that this will be solved?
I tried to just wrap the list up with brackets [list], but it did not work. I also did:
b = [[i] for i in a]
which gave me [[[0,1,2,3,4,5]],[[1,2,3,4,5,6]],...
and it still did not work!
NOTE: I want the i to be the row, j to be the column and k to be 0 or 1, so k = 0 (in which case the value is the row index of the cell is pointing to), or the k = 1 (the value is the column index).
Tried to reproduce your issue. To me, it works if you use the right index. Here, it perfectly works if you do for instance
print(a[0][0][5]) # I want to be able to print in 3D`
for list a = [[[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 2, 3, 4,5], [3, 2, 3, 4, 3, 4], [4, 3, 4, 5, 4, 3], [5, 4, 5, 6, 5, 4]]] you have just a[0][n][n]. You can try a[0][5][5]
You have index like below:
a = [
#0 element i
[
#0 element j
[0, 1, 2, 3, 4, 5],
#1 element j
[1, 2, 3, 4, 5, 6],
#2 element j
[2, 3, 2, 3, 4,5],
#3 element j
[3, 2, 3, 4, 3, 4],
#4 element j
[4, 3, 4, 5, 4, 3],
#5 element j
[5, 4, 5, 6, 5, 4]
]
]
print(a[0][5][5]) # a[i][j][k]

function that replaces consecutive duplicate elements of list with single element

What I tried :
def compress(l):
i = 0
while i < len(l)-1:
if l[i] == l[i+1]:
del l[i]
else:
i = i+1
l = [1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5]
compress(l)
I do not know many functions in python yet as I have just started so I would like to do this the basic way i.e using for and while loops and some list methods.
What am I doing wrong?
Any other methods
Another one I tried what's wrong in this :
def compress(l):
for i in l:
if l[i] == l[i+1] and i != (len(l) - 1):
l.pop(l[i])
print(l)
l = [1,1,1,1,2,2,2,2,2,2,3,3,3,4,5,6,7,8]
compress(l)
which gives me the output :
[1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 5, 6, 7, 8]
[1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 5, 6, 7, 8]
[1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 5, 6, 7, 8]
[1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 5, 6, 7, 8]
[1, 1, 2, 2, 2, 3, 3, 3, 4, 5, 6, 7, 8]
[1, 1, 2, 2, 3, 3, 3, 4, 5, 6, 7, 8]
[1, 1, 2, 2, 3, 3, 3, 4, 5, 6, 7, 8]
[1, 1, 2, 3, 3, 3, 4, 5, 6, 7, 8]
[1, 1, 2, 3, 3, 3, 4, 5, 6, 7, 8]
[1, 1, 2, 3, 3, 3, 4, 5, 6, 7, 8]
[1, 1, 2, 3, 3, 3, 4, 5, 6, 7, 8]
You don't appear to be doing anything wrong(a) with your first attempt, other than the fact you're not printing the compressed list. That can be fixed by adding this as the last line:
print(l)
At that point, you should see:
[1, 2, 3, 4, 5]
like I do.
Your second attempt is problematic - it's a common occurrence when you modify a list that you're iterating over. Because the iteration effectively examines based on the index, inserting items before the current point can result in items being processed twice. Additionally, deleting items at or before the current point can result in items not being processed at all.
That latter case is what's happening in your second attempt.
(a) You could probably choose more descriptive names for your variables than l but that's just a preference of mine.
Since you are asking for other methods, one should point out that repeated removal from a list has bad performance, as all the tail elements have to be shifted for each removal. Building the compressed list from scratch is less expensive and slice assignment allows you to mutate the original list. Using basic loops and list methods, I would do:
def compress(l):
new_l = l[:1]
for x in l:
if x != new_l[-1]:
new_l.append(x)
l[:] = new_l
For a one-line alternative using some more advanced means (itertools.groupby), you can do:
from itertools import groupby
def compress(l):
l[:] = [k for k, _ in groupby(l)]
You don't need to try so hard to delete duplicate elements in a list:
print(list(set(l)))
this will delete all the duplicate elements in the list.

Create 2d list from 1d list with given length and width? [duplicate]

This question already has answers here:
Create a 2D list out of 1D list
(3 answers)
Closed 1 year ago.
How to create 2D list from 1D list with given row and cols?
Given:
sample_list=[5, 2, 3, 4, 1, 6, 1, 6, 7, 2, 3]
row=2
cols=4
It should return this:
[[5, 2, 3, 4],[1, 6, 1, 6]]
I don't need other numbers = 7, 2, 3.
I just want a list that has row and cols which user gives.
My solution does not return what i want,
My solution:
def 1D_to_2D(sample_list, row, cols):
return [sample_list[i:i+cols] for i in range(0, len(sample_list), rows)]
returns:
[[5, 2, 3, 4], [3, 4, 1, 6], [1, 6, 1, 6], [1, 6, 7, 2], [7, 2, 3], [3]]
Anyone can help?
Just slice your list using a list comprehension with range and a step of cols (not rows as you used), and limit the number of items using external slicing with rows:
sample_list=[5, 2, 3, 4, 1, 6, 1, 6, 7, 2, 3]
rows=2
cols=4
result = [sample_list[x:x+cols] for x in range(0,len(sample_list),cols)][:rows]
result:
[[5, 2, 3, 4], [1, 6, 1, 6]]
def D_to_2D(sample_list, rows, cols):
return [sample_list[cols*i: cols*(i+1)] for i in range(rows)]
>>> D_to_2D([5, 2, 3, 4, 1, 6, 1, 6, 7, 2, 3], 2, 4)
[[5, 2, 3, 4], [1, 6, 1, 6]]
f = lambda x, row, cols: [x[i:i+cols] for i in range(0, cols*row, cols)]
f(x, row, cols)

How to sequentially aggregate the content of a dask Bag?

I would like to sequentially aggregate the content of a partitioned collection with an aggregation function that is not associative, therefore I cannot use Bag.fold or Bag.reduction.
There is Bag.accumulate that seems to do this operation, but it returns a bag with some per-partition intermediate results instead of just the final aggregate:
>>> import dask.bag as db
>>>
>>> def collect(acc, e):
... if acc is None:
... acc = list()
... acc.append(e)
... return acc
...
>>> b = db.from_sequence(range(10), npartitions=3)
>>> b.accumulate(collect, initial=None).compute()
[None,
[0, 1, 2, 3],
[0, 1, 2, 3],
[0, 1, 2, 3],
[0, 1, 2, 3],
[0, 1, 2, 3, 4, 5, 6, 7],
[0, 1, 2, 3, 4, 5, 6, 7],
[0, 1, 2, 3, 4, 5, 6, 7],
[0, 1, 2, 3, 4, 5, 6, 7],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]
Basically I am only interested in the last element of the accumulate output and I don't want to keep a copy of the intermediate steps in memory.
Bag doesn't currently have a sequential reduction operation, but it could. A simple way to accomplish this today would be to use use accumulate as you have above, but only ask for the last element of the last partition. We can do this relatively easily by converting the bag to delayed values using Bag.to_delayed
acc = b.accumulate(collect, initial=None)
partitions = acc.to_delayed()
partitions[-1][-1].compute()

Python - Read nth line in a matrix

What is the simplest way I can read the nth letter of a matrix?
I thought this would be possible with a simple for loop but so far I haven't had any luck.
The best I can do so far is using a count which is not exactly elegant:
matrix = [[1, 3, 5, 2, 6, 2, 4, 1], [2, 6, 1, 6, 2, 5, 7], [1, 6, 2, 6, 8, 2, 6]]
count = 0
for n in matrix:
print matrix[count][nth]
count += 1
For example:
Read the 0th number of every row: 1, 2, 1.
Read the 4th number of every row: 6, 2, 8.
If your need to do this operation a lot you could transpose your matrix using zip(*matrix)
>>> matrix = [[1, 3, 5, 2, 6, 2, 4, 1], [2, 6, 1, 6, 2, 5, 7], [1, 6, 2, 6, 8, 2, 6]]
>>> matrix_t = zip(*matrix)
>>> matrix_t
[(1, 2, 1), (3, 6, 6), (5, 1, 2), (2, 6, 6), (6, 2, 8), (2, 5, 2), (4, 7, 6)]
>>> matrix_t[0]
(1, 2, 1)
>>> matrix_t[3]
(2, 6, 6)
Here's something that will handle rows of different lengths (as in your example), as well as supporting Python's special interpretation of negative indexes as relative to the end of the sequence (by changing them intolen(s) + n):
NULL = type('NULL', (object,), {'__repr__': lambda self: '<NULL>'})()
def nth_elems(n):
abs_n = abs(n)
return [row[n] if abs_n < len(row) else NULL for row in matrix]
matrix = [[1, 3, 5, 2, 6, 2, 4, 1], [2, 6, 1, 6, 2, 5, 7], [1, 6, 2, 6, 8, 2, 6]]
print nth_elems(0) # [1, 2, 1]
print nth_elems(6) # [4, 7, 6]
print nth_elems(7) # [1, <NULL>, <NULL>]
print nth_elems(-1) # [1, 7, 6]
Maybe this way?
column = [row[0] for row in matrix]
(for the 0th element)
In [1]: matrix = [[1, 3, 5, 2, 6, 2, 4, 1], [2, 6, 1, 6, 2, 5, 7], [1, 6, 2, 6, 8, 2, 6]]
In [2]: nth=0
In [3]: [row[nth] for row in matrix]
Out[3]: [1, 2, 1]
In [4]: nth=4
In [5]: [row[nth] for row in matrix]
Out[5]: [6, 2, 8]
Here is a solution using list comprehension:
[x[0] for x in matrix]
Which is basically, equal to:
for x in matrix:
print x[0]
You can also make it a function:
def getColumn(lst, col):
return [i[col] for i in lst]
Demo:
>>> matrix = [[1, 3, 5, 2, 6, 2, 4, 1], [2, 6, 1, 6, 2, 5, 7], [1, 6, 2, 6, 8, 2, 6]]
>>> def getColumn(lst, col):
return [i[col] for i in lst]
>>> getColumn(matrix, 0)
[1, 2, 1]
>>> getColumn(matrix, 5)
[2, 5, 2]
Hope this helps!
List comprehensions will work well here:
>>> matrix = [[1, 3, 5, 2, 6, 2, 4, 1], [2, 6, 1, 6, 2, 5, 7], [1, 6, 2, 6, 8, 2, 6]]
>>> # Get all the 0th indexes
>>> a = [item[0] for item in matrix]
>>> a
[1, 2, 1]
>>> # Get all the 4th indexes
>>> b = [item[4] for item in matrix]
>>> b
[6, 2, 8]
>>>
Your for loop is likely not doing what you expect. n is not an integer. It is the current row.
I think what you wanted to do was:
for row in matrix:
print row[0], row[4]
This prints,
1 6
2 2
1 8
Also, strictly speaking, matrix is a list of lists. To really have a matrix you might need to use numpy.
Lists in Python are not intended to be used like this. Using list comprehension may cause both memory and CPU issues if the data is sufficiently big. Consider using numpy if this is an issue.
Use zip:
>>> matrix = [[1, 3, 5, 2, 6, 2, 4, 1], [2, 6, 1, 6, 2, 5, 7], [1, 6, 2, 6, 8, 2, 6]]
>>> zip(*matrix)[0]
(1, 2, 1)
>>> zip(*matrix)[4]
(6, 2, 8)

Categories

Resources