How to make a set of lists - python

I have a list of lists like this:
i = [[1, 2, 3], [2, 4, 5], [1, 2, 3], [2, 4, 5]]
I would like to get a list containing "unique" lists (based on their elements) like:
o = [[1, 2, 3], [2, 4, 5]]
I cannot use set() as there are non-hashable elements in the list. Instead, I am doing this:
o = []
for e in i:
if e not in o:
o.append(e)
Is there an easier way to do this?

You can create a set of tuples, a set of lists will not be possible because of non hashable elements as you mentioned.
>>> l = [[1, 2, 3], [2, 4, 5], [1, 2, 3], [2, 4, 5]]
>>> set(tuple(i) for i in l)
{(1, 2, 3), (2, 4, 5)}

i = [[1, 2, 3], [2, 4, 5], [1, 2, 3], [2, 4, 5]]
print([ele for ind, ele in enumerate(i) if ele not in i[:ind]])
[[1, 2, 3], [2, 4, 5]]
If you consider [2, 4, 5] to be equal to [2, 5, 4] then you will need to do further checks

You can convert each element to a tuple and then insert it in a set.
Here's some code with your example:
tmp = set()
a = [[1, 2, 3], [2, 4, 5], [1, 2, 3], [2, 4, 5]]
for i in a:
tmp.add(tuple(i))
tmp will be like this:
{(1, 2, 3), (2, 4, 5)}

Here's another way to do it:
I = [[1, 2, 3], [2, 4, 5], [1, 2, 3], [2, 4, 5]]
mySet = set()
for j in range(len(I)):
mySet = mySet | set([tuple(I[j])])
print(mySet)

Related

how to merge lists in list (without numpy)

This is what i have-
def merge_list(mylist)
list1 = []
one_len = len(mylist)
two_len = len(mylist[0][0])
for index in range(two_len):
combine_list = []
for index2 in range(one_len):
combine_list.extend([a[index] for a in mylist[
index2]])
list1.append(combine_list)
return list1
But i have a problem with the output-
for example:
input-
mylist=[[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]], [[2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2]], [[3, 3, 3], [3, 3, 3], [3, 3, 3], [3, 3, 3]]]
in short-
[[[1]*3]*4, [[2]*3]*4, [[3]*3]*4]
the output is -
[[[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3], [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3], [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]]]
and not -
[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]
in short-
[[[1, 2, 3]]*3]*4
I would be happy to solve the problem and advise how to shorten the code.
In order to fix your code, you just need to update the return statement like this:
return [list1]
Though there is still a hidden problem when your inner lists lengths are longer than one element. Check your outputs with sample inputs like [[[2,1], [3,1]]].
One further - more compact - solution may be obtained by concatenating the inner lists within a cycle, then recreate the number of dimensions you need, moving the complexity from O(n^2) to O(n).
mylist = [[[2,1]],[[3,1]]]
def merge_list(mylist):
l_out = []
for l in mylist:
l_out += l[0]
return [[l_out]]
EDIT: In case of more complex inputs, you can extract first all elements and eventually fix the dimensions. This will still bring O(n^2) complexity though:
def merge_list(lst):
elements = [[] for _ in range(len(mylist[0]))]
for l1 in mylist:
for idx, l2 in enumerate(l1):
elements[idx] += l2
return [elements]
merge_list(mylist)
Input:
[[[1], [1]], [[2], [2]], [[3], [3]]]
Output:
[[[1, 2, 3], [1, 2, 3]]]

Python group list into subgroups with constraints

I really searched for this one, because I am almost certain some variation has been asked before but I couldn't put in the correct terms into Google to get a result that matches what I am trying to do. Generally seems like people are looking for the total combinations without constraints.
I am trying to do the following:
Given a list like this:
[1, 1, 2, 2, 3, 3] group it into as many groups of [1, 2, 3] as possible
So
[1, 1, 2, 2, 3, 3] -> [[1, 2, 3], [1, 2, 3]]
[1, 1, 2, 3, 3] -> [[1, 2, 3], [1, 3]]
[1, 1, 3, 3, 5] -> [[1, 3, 5], [1, 3]]
[1, 4, 4, 7] -> [[1, 4, 7], [4]]
Notes:
Input will always be sorted, but the values of these numbers is not known, so it will need to work in general sense.
The idea is I have objects with certain attributes that need to be grouped together to create a different object, but sometimes I am given repeats (and potentially incomplete repeats) -- ie, I used to think that the attributes of my objects will always just be [1, 2, 3] but turns out sometimes I can get [1, 1, 2, 2, 3, 3] and I need a way to break that into two [1, 2, 3] lists to create an intermediate object downstream.
You can use zip_longest and groupby from itertools:
from itertools import zip_longest, groupby
def f(l):
z = zip_longest(*[list(g) for _, g in groupby(l)])
return [[j for j in i if j is not None] for i in z]
Usage:
>>> f([1, 1, 2, 2, 3, 3])
[[1, 2, 3], [1, 2, 3]]
>>> f([1, 1, 2, 3, 3])
[[1, 2, 3], [1, 3]]
>>> f([1, 1, 3, 3, 5])
[[1, 3, 5], [1, 3]]
>>> f([1, 4, 4, 7])
[[1, 4, 7], [4]]
# Update
>>> f(sorted([1, 1, 2, 2, 3, 3, 1, 2]))
[[1, 2, 3], [1, 2, 3], [1, 2]]
# Update 2
>>> f([1, 1, 1, 2, 2, 2, 3, 3])
[[1, 2, 3], [1, 2, 3], [1, 2]]
Update
Alternative version suggested by #cards using filterfalse:
from itertools import zip_longest, groupby, filterfalse
def f(l):
z = zip_longest(*[list(g) for _, g in groupby(l)])
return [list(filterfalse(lambda j: j is None, i)) for i in z]

A pure python equivalent of A[R][:,R]

I want to perform the equivalent of the numpy
A[R][:,R]
but in pure python. As an example:
A = [[0, 1, 2], [1, 2, 3], [2, 3, 4]] and
R = [1, 2, 2]
the output should be:
[[2, 3, 3],[3, 4, 4], [3, 4, 4]]
Is there a nice way to do that in pure python?
I guess that would be [[A[i][k] for k in R] for i in R]
>>> A = [[0, 1, 2], [1, 2, 3], [2, 3, 4]] ; R = [1, 2, 2]
>>> np.array(A)[R][:,R]
array([[2, 3, 3],
[3, 4, 4],
[3, 4, 4]])
>>> [[A[i][k] for k in R] for i in R]
[[2, 3, 3], [3, 4, 4], [3, 4, 4]]
The closest built-in ability to numpy's "indexing with a list" is operator.itemgetter() with multiple parameters:
>>> import operator
>>> g = operator.itemgetter(*R)
>>> [g(row) for row in g(A)]
[(2, 3, 3), (3, 4, 4), (3, 4, 4)]

How to create a list from tuples with sub-tuples?

I have two lists a and b. Then I create all combinations taking all two-length combinations of a plus one each of b:
import itertools as it
a = [1,2,3,4]
b = [5,6]
for i in it.product(it.combinations(a, 2), b):
print (i)
# output:
((1, 2), 5)
((1, 2), 6)
((1, 3), 5)
...
# expected output:
[1, 2, 5]
[1, 2, 6]
[1, 3, 5]
...
How can the tuples be transformed at the stage of the loop operation into lists?
The following comprehensions will work:
>>> [[*x, y] for x, y in it.product(it.combinations(a, 2), b)] # Py3
>>> [list(x) + [y] for x, y in it.product(it.combinations(a, 2), b)] # all Py versions
[[1, 2, 5],
[1, 2, 6],
[1, 3, 5],
[1, 3, 6],
[1, 4, 5],
[1, 4, 6],
[2, 3, 5],
[2, 3, 6],
[2, 4, 5],
[2, 4, 6],
[3, 4, 5],
[3, 4, 6]]
Simplified approach:
a = [1,2,3,4]
b = [5,6]
l = len(a)
print(sorted([a[i], a[i_n], j] for i in range(l) for j in b
for i_n in range(i+1, l) if i < l-1))
The output:
[[1, 2, 5], [1, 2, 6], [1, 3, 5], [1, 3, 6], [1, 4, 5], [1, 4, 6], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6], [3, 4, 5], [3, 4, 6]]

generate all k-Permutations from n+1 without recalculate the k-permutations from n python 3

My task is to calculate the k-permutations from the updated List by new element
without recalculating the k-permutations already gotten from the previous state of the list. Example:
liste = [1, 2, 3]
3-permutations are:
[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]
The updated list:
liste = [1, 2, 3, 4]
I would like to obtain directly 3-permutations[1, 2, 3, 4]-3-permutations[1, 2, 3]
without recalculating 3-permutations[1, 2, 3]
Calculate directly the new permutations:
[1, 2, 4], [1, 3, 4], [1, 4, 2], [1, 4, 3], [2, 1, 4], [2, 3, 4], [2, 4, 1],
[2, 4, 3], [3, 1, 4], [3, 2, 4], [3, 4, 1], [3, 4, 2], [4, 1, 2], [4, 1, 3],
[4, 2, 1], [4, 2, 3], [4, 3, 1], [4, 3, 2]
Thanks
Computing first the cartesian product {0,1,2,3}x{0,1,2}x{0,1} and taking the nth element of list (1,2,3,4).
r=[]
for prd in itertools.product([[0,1,2,3],[0,1,2],[0,1]]):
l=[1,2,3,4]
r0=[]
for i in prd:
r0 += l[i]
del l[i]
r += r0
EDIT: original answer gives the 3-permutations of [1,2,3,4]
following command answers specifically to question, see how it can be generalized
[list(j) for i in itertools.combinations([1,2,3],2) for j in itertools.permutations(list(i)+[4])]
next case, maybe one of ?
[list(j) for i in itertools.combinations([1,2,3],2) for j in itertools.permutations(list(i)+[4,5])]
[list(j) for i in itertools.combinations([1,2,3,4],3) for j in itertools.permutations(list(i)+[4,5])]
try saving the existing permutations to a list, then do:
if newPermutation not in listOfExistingPermutations:
listOfExistingPermutations.append(newPermutation)
or something along those lines

Categories

Resources