Python iterate over array of arrays special way - python

I have this array of arrays:
[[[1111, 2222, 3333], [4444, 5555, 6666]], [[7777]], [[8888, 9999]], [[0000]], [[1122, 2233]]]
I need to get all the possible combinations IN ORDER of the elements of the list.
Expected output for this example:
[1111,2222,3333,7777,8888,9999,0000,1122,2233]
[4444, 5555, 6666,7777,8888,9999,0000,1122,2233]
As you may see in this example the first array of the array is the only one who has two options.
I've tried with something like:
for i in array_input:
for j in i:
print ', '.join([str(x) for x in j]),
but that is not getting me the expected output because is firstly iterating through the two array[0] options instead of picking one of them and filling the rest and then picking the other one and filling it.
So I want some loop that gets array[0][0],array[1][0],array[2][0]... instead of: array[0][0],array[0][1],array[1][0]...
thank you

Your elements are integers, so 0000 will be shown as 0:
import itertools as it
lst = [[[1111, 2222, 3333], [4444, 5555, 6666]], [[7777]], [[8888, 9999]], [[0000]], [[1122, 2233]]]
out = [list(it.chain.from_iterable(x)) for x in it.product(*lst)]
First itertools.product generates a product of all arguments. Then you need itertools.chain.from_iterable to flatten the list of lists.

You could use itertools.combinations, lets simplify your example to the list `l = ['a', 'b', 'c', 'd'] then you can generate all combinations of length r with:(here i.e. r = 3)
import itertools as it
l = ['a', 'b', 'c', 'd']
for e in it.combinations(l, 3):
print e
=> ('a', 'b', 'c')
('a', 'b', 'd')
('a', 'c', 'd')
('b', 'c', 'd')
if you want to get all combinations just loop your r over the length of l
to overcome the problem with the two arrays you could maybe flatten your list i.e. with something like
new_list = [item for sublist in l for item in sublist]
full example:
import itertools as it
l = [[[1111, 2222, 3333], [4444, 5555, 6666]], [[7777]], [[8888, 9999]], [[0000]], [[1122, 2233]]]
l = [item for sublist in l for item in sublist]
for n in range(1, len(l)):
for e in it.combinations(l, n):
print e

You can just do the following ...
import operator
reduce(operator.__add__, zip(*array_input)[0])
The zip(*array_input) basically unzips the array to ...
[([1111, 2222, 3333], [7777], [8888, 9999], [0], [1122, 2233])]
zip(*array_input)[0] simply remove one level of nesting ...
Finally the reduce operator adds the lists to a single list. You could also have done
reduce(lambda m, n: m+n, zip(*array_input)[0]) but I don't like using lambda functions here ...

list1 = [[[1111, 2222, 3333], [4444, 5555, 6666]], [[7777]], [[8888, 9999]], [[0000]], [[1122, 2233]]]
a = []
for i in list1:
for j in i:
for k in j:
a.append(k)
print(a)

Related

generating list of every combination without duplicates

I would like to generate a list of combinations. I will try to simplify my problem to make it understandable.
We have 3 variables :
x : number of letters
k : number of groups
n : number of letters per group
I would like to generate using python a list of every possible combinations, without any duplicate knowing that : i don't care about the order of the groups and the order of the letters within a group.
As an example, with x = 4, k = 2, n = 2 :
# we start with 4 letters, we want to make 2 groups of 2 letters
letters = ['A','B','C','D']
# here would be a code that generate the list
# Here is the result that is very simple, only 3 combinations exist.
combos = [ ['AB', 'CD'], ['AC', 'BD'], ['AD', 'BC'] ]
Since I don't care about the order of or within the groups, and letters within a group, ['AB', 'CD'] and ['DC', 'BA'] is a duplicate.
This is a simplification of my real problem, which has those values : x = 12, k = 4, n = 3. I tried to use some functions from itertools, but with that many letters my computer freezes because it's too many combinations.
Another way of seeing the problem : you have 12 players, you want to make 4 teams of 3 players. What are all the possibilities ?
Could anyone help me to find an optimized solution to generate this list?
There will certainly be more sophisticated/efficient ways of doing this, but here's an approach that works in a reasonable amount of time for your example and should be easy enough to adapt for other cases.
It generates unique teams and unique combinations thereof, as per your specifications.
from itertools import combinations
# this assumes that team_size * team_num == len(players) is a given
team_size = 3
team_num = 4
players = list('ABCDEFGHIJKL')
unique_teams = [set(c) for c in combinations(players, team_size)]
def duplicate_player(combo):
"""Returns True if a player occurs in more than one team"""
return len(set.union(*combo)) < len(players)
result = (combo for combo in combinations(unique_teams, team_num) if not duplicate_player(combo))
result is a generator that can be iterated or turned into a list with list(result). On kaggle.com, it takes a minute or so to generate the whole list of all possible combinations (a total of 15400, in line with the computations by #beaker and #John Coleman in the comments). The teams are tuples of sets that look like this:
[({'A', 'B', 'C'}, {'D', 'E', 'F'}, {'G', 'H', 'I'}, {'J', 'K', 'L'}),
({'A', 'B', 'C'}, {'D', 'E', 'F'}, {'G', 'H', 'J'}, {'I', 'K', 'L'}),
({'A', 'B', 'C'}, {'D', 'E', 'F'}, {'G', 'H', 'K'}, {'I', 'J', 'L'}),
...
]
If you want, you can cast them into strings by calling ''.join() on each of them.
Another solution (players are numbered 0, 1, ...):
import itertools
def equipartitions(base_count: int, group_size: int):
if base_count % group_size != 0:
raise ValueError("group_count must divide base_count")
return set(_equipartitions(frozenset(range(base_count)), group_size))
def _equipartitions(base_set: frozenset, group_size: int):
if not base_set:
yield frozenset()
for combo in itertools.combinations(base_set, group_size):
for rest in _equipartitions(base_set.difference(frozenset(combo)), group_size):
yield frozenset({frozenset(combo), *rest})
all_combinations = [
[tuple(team) for team in combo]
for combo in equipartitions(12, 3)
]
print(all_combinations)
print(len(all_combinations))
And another:
import itertools
from typing import Iterable
def equipartitions(players: Iterable, team_size: int):
if len(players) % team_size != 0:
raise ValueError("group_count must divide base_count")
return _equipartitions(set(players), team_size)
def _equipartitions(players: set, team_size: int):
if not players:
yield []
return
first_player, *other_players = players
for other_team_members in itertools.combinations(other_players, team_size-1):
first_team = {first_player, *other_team_members}
for other_teams in _equipartitions(set(other_players) - set(first_team), team_size):
yield [first_team, *other_teams]
all_combinations = [
{''.join(sorted(team)) for team in combo} for combo in equipartitions(players='ABCDEFGHIJKL', team_size=3)
]
print(all_combinations)
print(len(all_combinations))
Firstly, you can use a list comprehension to give you all of the possible combinations (regardless of the duplicates):
comb = [(a,b) for a in letters for b in letters if a != b]
And, afterwards, you can use the sorted function to sort the tuples. After that, to remove the duplicates, you can convert all of the items to a set and then back to a list.
var = [tuple(sorted(sub)) for sub in comb]
var = list(set(var))
You could use the list comprehension approach, which has a time complexity of O(n*n-1), or you could use a more verbose way, but with a slightly better time complexity of O(n^2-n)/2:
comb = []
for first_letter_idx, _ in enumerate(letters):
for sec_letter_idx in range(first_letter_idx + 1, len(letters)):
comb.append(letters[first_letter_idx] + letters[sec_letter_idx])
print(comb)
comb2 = []
for first_letter_idx, _ in enumerate(comb):
for sec_letter_idx in range(first_letter_idx + 1, len(comb)):
if (comb[first_letter_idx][0] not in comb[sec_letter_idx]
and comb[first_letter_idx][1] not in comb[sec_letter_idx]):
comb2.append([comb[first_letter_idx], comb[sec_letter_idx]])
print(comb2)
This algorithm needs more work to handle dynamic inputs. Maybe with recursion.
Use combination from itertools
from itertools import combinations
x = list(combinations(['A','B','C','D'],2))
t = []
for i in (x):
t.append(i[0]+i[1]) # concatenating the strings and adding in a list
g = []
for i in range(0,len(t),2):
for j in range(i+1,len(t)):
g.append([t[i],t[j]])
break
print(g)

How to create a new list of tuples with existing list of tuples

I have a list of tuples like this -
list1 = [('alpha', 'beta'),
('beta','gama')
('alpha','lamda')
('gama', 'lamda'),
('euphor', 'tuphor')]
And I want to make a new list based upon the logic that -
for every pair which doesn't exist in the original list will be included in the new list, like the following:
new_list = [('alpha','gama'),
(alpha, tuphor),
(alpha, euphor),
(beta,lamda),
()...]
likewise.
Can anyone suggest the method for doing so in python?
Thanks.
from itertools import combinations
list1 = [('alpha', 'beta'),
('beta','gama'),
('alpha','lamda'),
('gama', 'lamda'),
('euphor', 'tuphor')]
elements = list(set([e for l in list1 for e in l])) # find all unique elements
complete_list = list(combinations(elements, 2)) # generate all possible combinations
#convert to sets to negate the order
set1 = [set(l) for l in list1]
complete_set = [set(l) for l in complete_list]
# find sets in `complete_set` but not in `set1`
ans = [list(l) for l in complete_set if l not in set1]
Output :
[['euphor', 'lamda'],
['euphor', 'gama'],
['euphor', 'beta'],
['euphor', 'alpha'],
['lamda', 'beta'],
['lamda', 'tuphor'],
['gama', 'alpha'],
['gama', 'tuphor'],
['beta', 'tuphor'],
['tuphor', 'alpha']]
Here's a solution using itertools and sets:
list1 = [('alpha', 'beta'),
('beta','gama'),
('alpha','lamda'),
('gama', 'lamda'),
('euphor', 'tuphor')]
all_items = set(itertools.chain(*list1))
all_pairs = set(itertools.product(all_items, all_items))
new_pairs = all_pairs.difference(list1)
The result (new_pairs) is:
{('alpha', 'alpha'),
('alpha', 'euphor'),
('alpha', 'gama'),
('alpha', 'tuphor'),
('beta', 'alpha'),
('beta', 'beta'),
('beta', 'euphor'),
('beta', 'lamda'),
('beta', 'tuphor'),
...
You just need to get the unique names in the original list and then apply the if condition. Try this and let me know if you face any issue.
new_list = []
names = set(np.array(list1).ravel())
for i in names:
for j in names:
if i!=j:
if ((i,j) not in list1) & ((j,i) not in list1) & ((i,j) not in new_list) & ((j,i) not in new_list):
new_list.append((i,j))
You may
collect the different items
compute all the permutations
get the difference between all the combinations and the existing ones
list1 = [('alpha', 'beta'), ('beta', 'gama'), ('alpha', 'lamda'), ('gama', 'lamda'), ('euphor', 'tuphor')]
from itertools import chain, combinations
items = set(chain(*list1)) # {'euphor', 'gama', 'tuphor', 'beta', 'lamda', 'alpha'}
all_perm = set(combinations(items, r=2))
new_perm = all_perm - set(list1)
print(len(all_perm), all_perm) # 30
print(len(new_perm), new_perm) # 25

How to remove multiple items from nested list in python 3?

How to remove multiple items from nested list in python 3, without using a list comprehension? And at times Indexerror came how to handle that?
split_list =[["a","b","c"],["SUB","d","e",],["f","Billing"]]
rem_word = ['SUB', 'Billing', 'Independent', 'DR']
for sub_list in split_list:
for sub_itm in sub_list:
if sub_itm not in rem_word:
print(sub_itm)
Output Comes like this:
a
b
c
d
e
f
Expected Output:
split_list =[["a","b","c"],["d","e",],["f"]]
You can use always use a list-comprehension. Get all the words to be removed in a separate list and try this :
>>> split_list =[["a","b","c"],["SUB","d","e",],["f","Billing"]]
>>> rem_word = ['SUB', 'Billing', 'Independent', 'DR']
>>> output = [[sub_itm for sub_itm in sub_list if sub_itm not in rem_word] for sub_list in split_list]
[['a', 'b', 'c'], ['d', 'e'], ['f']]
If you want to do it without list comprehension, you need to declare a vacant list to append each new sub-list and also a new vacant sub-list to append all new sub-items. Check this :
output2 = []
for sub_list in split_list:
new_sub_list = []
for sub_itm in sub_list:
if sub_itm not in rem_word:
new_sub_list.append(sub_itm)
output2.append(new_sub_list)
It outputs the same :
[['a', 'b', 'c'], ['d', 'e'], ['f']]
You could simply use map and filter
split_list = [["a", "b", "c"], ["SUB", "d", "e", ], ["f", "Billing"]]
remove_list = ["SUB", "Billing", "INDEPENDENT", "DR"]
split_list = list(map(lambda x: list(filter(lambda i: i not in remove_list, x)), split_list))
print(split_list)
[[x for x in z if x!='SUB'] for z in split_list]
keep in mind that it is a nested list. Treat x as the sub element and z as the element. Also keep in mind that the above code will delete all 'SUB'. just for deleting the first instance use remove.

Flatten lists of variable depths in Python

I have a list of n lists. Each internal list contains a combination of (a) strings, (b) the empty list, or (c) a list containing one string. I would like to transform the inside lists so they only contain the strings.
I have a list like this for example:
[[[],["a"],"a"],[["ab"],[],"abc"]]
and I would like it to be like this:
[["","a","a"],["ab","","abc"]]
I know I could probably go through with a loop but I am looking for a more elegant solution, preferably with a list comprehension.
List comprehension:
>>> original = [[[],["a"],"a"],[["ab"],[],"abc"]]
>>> result = [['' if not item else ''.join(item) for item in sublist] for sublist in original]
>>> result
[['', 'a', 'a'], ['ab', '', 'abc']]
As every element of the list that you'd like to flatten is iterable, instead of checking of being instance of some class (list, string) you can actually make use of duck-typing:
>> my_list = [[[],["a"],"a"],[["ab"],[],"abc"]]
>> [list(map(lambda x: ''.join(x), elem)) for elem in my_list]
Or more readable version:
result = []
for elem in my_list:
flatten = map(lambda x: ''.join(x), elem)
result.append(list(flatten))
Result:
[['', 'a', 'a'], ['ab', '', 'abc']]
It's quite pythonic to not to check what something is but rather leverage transformation mechanics to adaptive abilities of each of the structure.
Via list comprehension:
lst = [[[],["a"],"a"],[["ab"],[],"abc"]]
result = [ ['' if not v else (v[0] if isinstance(v, list) else v) for v in sub_l]
for sub_l in lst ]
print(result)
The output:
[['', 'a', 'a'], ['ab', '', 'abc']]
original_list = [[[],["a"],"a"],[["ab"],[],"abc"]]
flatten = lambda x: "" if x == [] else x[0] if isinstance(x, list) else x
flattened_list = [[flatten(i) for i in j] for j in original_list]

How to create a list from lists?

fp.readline()
for line in fp:
line_lst = line.strip().split(',')
Suppose I get a bunch of lists after running the code above:
['a','b','c']['1','2','3']['A','B','C']
How could I get another lists
['a','1','A']['b','2','B']['c','3','C']
from the lists instead of directly creating it?
Assuming all lists have same number of elements
my_lists = [my_list_1, my_list2, ...]
for i in xrange(len(my_lists[0])):
print [l[i] for l in my_lists]
An example...
>>> my_lists = [['a','b','c'],['1','2','3'],['A','B','C']]
>>> for i in xrange(len(my_lists[0])):
... print [l[i] for l in my_lists]
...
['a', '1', 'A']
['b', '2', 'B']
['c', '3', 'C']
You could use
all_list = [['a','b','c'],['1','2','3'],['A','B','C']]
result = [x[0] for x in all_list]
print(result)
This is called list comprehension in Python.
For your need, you should use zip function here, the link is give by #Arc676.
all_list = [['a','b','c'],['1','2','3'],['A','B','C']]
# result = list(zip(all_list[0], all_list[1], all_list[2]))
# if you have more list in all_list, you could use this
result = list(zip(*all_list))
print(result)
You could try something like below.
var aggregateList = line_lst.map(function (value) { return value[0]; });
EDIT: Oops, thought I was in the javascript section, for python:
aggregateList = map(lambda value: value[0], line_lst)
This should do it... but it's really just getting the first item from each list, so I'm not sure if it's exactly what you want
new_list = []
for sub_list in line_lst:
new_list.append(sub_list[0])
you could also do this (which I like better)
new_list = [sub_list[0] for sub_list in line_lst]
Just:
zip(['a','b','c'], ['1','2','3'], ['A','B','C'])
Which gives:
[('a', '1', 'A'), ('b', '2', 'B'), ('c', '3', 'C')]

Categories