Combinations of a list of list - Elementwise - python

I am looking for a method to generate all possible combinations of a list of lists, under the condition that there should only be "elementwise" combinations. Thus, if we have the lists [1,2] and [3,4], then the outcome [3,2] is allowed, but [4,2] is not allowed. With itertools.product(*lists) the last outcome is included.
Thus, I want the following output: [1,2], [3,2], [1,4], [3,4], and the following options should be 'skipped': [4,2], [1,3]. Note that the order is important! Thus I do not allow [2,3], just [3,2].
I know that I can check for this afterwards, but since I am generating many many lists in my code, I rather avoid this.

You could store the two lists in one list of lists and then after transposing the container list, use itertools.product() on it.
import itertools
original_list = [[1,2], [3,4]]
transposed_list = list(map(list, zip(*original_list)))
print(list(itertools.product(*transposed_list)))
Outputs:
[(1, 2), (1, 4), (3, 2), (3, 4)]
EDIT | Explaining how the list was transposed:
By definition, transposing is the process of exchanging places.
*original_list means [1,2] and [3,4]. The asterisk refers to the elements of the list, rather than the list as a whole
zip basically pairs values together 'element-wise':
e.g. with our original_list we have [1,2] and [3,4]. Calling zip on our elements will result in (1,3) and (2,4). The values were paired element-wise.
Note that the resulting pairs are not in list form.
map applies a function to every element in an input list. In our example,
we want to apply the (built-in) list function to our element-wise pairs - i.e. convert each tuple of pairs into a list. This is what turns (1,3) and (2,4) into [1,3] and [2,4]
Finally, convert our result from the mapping into a containing list, holding our element-wise pairs, producing [ [1,3], [2,4] ]

Related

Sum of elements of a 2d list in Python

I have a 2D list
a = [[1,2], [3,4] ...]
I want to do something like this:
1+3 and 2+4 and store result in another array
b = [4, 6]
Like 0th element of array at index 0 which is 1, added with 0th element of array at index 1 which is 3, and 2 added with 4, and so on.
How can I do this, without looping or generators as looping over a large list is comparatively slower than sum and zip functions.
Using just sum and zip as you mention, however zip still returns a generator, which is memory efficient, not sure why you think otherwise.
list(map(sum, (zip(*a))))

How to select multiple sets of elements from a list

I want to select multiple groups of three or more elements from a list, according to some indices.
I thought of using itemgetter, but it does not work for multiple sets, for example
labels=['C1','C2','C3','C4','C5','C6','C7','C8','C10','C13','C14','C15']
indexlist = list(itertools.combinations(range(1, 10), 3))
ixs= [4,5]
a=[indexlist[ix] for ix in ixs]
from operator import itemgetter
print(*itemgetter(*a[0])(labels))
where
a=[(1, 2, 7), (1, 2, 8)]
works well, whereas
labels=['C1','C2','C3','C4','C5','C6','C7','C8','C10','C13','C14','C15']
indexlist = list(itertools.combinations(range(1, 10), 3))
ixs= [4,5]
a=[indexlist[ix] for ix in ixs]
from operator import itemgetter
print(*itemgetter(*a)(labels))
gives the error
list indices must be integers or slices, not list
Is there a way to pass multiple sets of indices to itemgetter, or is there some other convenient alternative?
You are trying to parse several indexes, as stated. To make it easier you can use numpy.
labels = np.array(['C1','C2','C3','C4','C5','C6','C7','C8','C10','C13','C14','C15'])
print([list(labels[index_tuples])] for index_tuples in a)
What this is doing is getting multiple sets of indexes using your tuples and printing them as a list.
Source: Access multiple elements of list knowing their index

Reorganizing a list of tuples into lists of floats

Say I have in python a list of tuples
list1 = [(1,1,1), (2,2,2), (3,3,3)]
If I want to separate them into a list of all the 1 position values, 2 position values and 3 position values I would do:
ones = [tuple[0] for tuple in list1]
twos = [tuple[1] for tuple in list1]
threes = [tuple[2] for tuple in list1]
This sort of way can become very cumbersome the more elements each tuple in that list will have. Is there a cleaner way to do this possibly using the zip method or a reverse of it?
You can use zip for this:
list(zip(*list1))
output:
[(1, 2, 3), (1, 2, 3), (1, 2, 3)]
As #paoloaq noted, you can unpack these into separate lists:
ones, two, threes = list(zip(*list1))
or if you want lists instead of tuples:
ones, two, threes = map(list, list(zip(*list1)))
Sidenote: try avoiding variable names like list and tuple.

Fast algorithm needed for finding tuples from within one list inside tuples of another list. Sets?

I have following lists:
list_1 = [(0, 1, 7, 6), (1, 2, 8, 7), (2, 3, 9, 8), ...]
list_2 = [(0,1), (1,7), (7,8), (3,9), ...]
Both lists have a length of 200000 or more elements.
I need a fast algorithm to check how often an element of list_2 occurs in an element of list_1. In the example above, the second element of list_2 which is (1,7) occurs two times in list_1, respectively in the first and second list element.
In my case it is a valid hit, if both numbers are a subset of list_1 independent of their order. So I thought I go with sets and use .issubset.
for item1 in list_1:
count = 0
for item2 in list_2:
if set(item2).issubset(set(item1)):
count += count
if count == 1:
do this
if count == 2:
do that
The data from the lists are structured in a way, that I know upfront, that the variable count can only have the values 1 or 2. And I know that a loop of O(N**2) is not smart at all and that the if statements in it do not boost performance. Actually, in my current implementation the elements of list_2 are already of type set, but the snippet above is shorter and easy to read.
I believe that there are smart solutions existing for this task.
My application uses numpy and scipy, so any KD-tree search or similar (if applicable) would also be fine.
EDIT
I need to be more specific:
list_2 always contains pairs. list_1 can have 3 or more items per list element.
in do this and do that I need to keep track of the corresponding elements and their associations, e.g by using a dictionary.
there is not more than this to exploit the structure of the data
You could first do some preprocessing and build a dictionary keyed by the individual numbers that occur in list_1 providing each key as value the set of tuples in list_1 that have that keys.
Then finding the occurrences of a pair from list_2 is as simple as taking the intersection of the sets found at the two keys, and taking the resulting set's size.
list_1 = [(0, 1, 7, 6), (1, 2, 8, 7), (2, 3, 9, 8)]
list_2 = [(0,1), (1,7), (7,8), (3,9)]
# per number as dictionary key, list the tuples from list_1 that contain it
d = dict()
for lst in list_1:
for v in lst:
if not v in d: d[v] = set()
d[v].add(lst)
# for each pair, take the intersection of the corresponding lists in d
result = [(lst, len(d[lst[0]].intersection(d[lst[1]]))) for lst in list_2]
print(result)
If you need to actually do something with the found tuples from list_1, then you would first gather those tuples without taking their number (so d[lst[0]].intersection(d[lst[1]])), and do your processing on them based on what len() provides (1 or 2).

Enumerating all possibilites for a nondeterministic list

I'm working with lists that could have "ambiguous" values in certain places. The lists are small enough that implementing backtracking search seems silly. Currently, I'm representing ambiguous values in my lists with sub-lists containing possible values. For instance, the list:
[1, 2, [3,4]]
Could be either the list [1,2,3] or [1,2,4]. Lists may have multiple ambiguous values in them, though ambiguous elements may not themselves contain ambiguous elements. Given a list with ambiguous values in it, I'm trying to generate a list of all the possible lists that list could represent. The previous list should return [[1,2,3],[1,2,4]].
Is there an elegant way to do this? I tried to recursively build each list backwards and append to an empty list, but I can't quite wrap my brain around how to do it.
You can use itertools.product, but you'll have to modify your source list slightly:
>>> import itertools
>>> l = [[1], [2], [3, 4]]
>>> list(itertools.product(*l))
[(1, 2, 3), (1, 2, 4)]

Categories