generate all combinations from list of numbers,the combinations can be pair of two numbers
example 1 : list of 2 numbers [1,2]
[
[[1],[2]],
[[1,2]]
]
example 2 : list of 3 numbers [1,2,3]
[
[[1], [2], [3]],
[[1], [2, 3]],
[[1, 3], [2]],
[[1, 2], [3]]
]
example 3 : list of 4 numbers [1,2,3,4]
[
[[1], [2], [3], [4]]
[[1], [2], [3, 4]],
[[1], [2, 4], [3]],
[[1], [2, 3], [4]],
[[1, 4], [2], [3]],
[[1, 3], [2], [4]],
[[1, 2], [3], [4]],
[[1, 2], [3, 4]],
[[1, 3], [2, 4]],
[[1, 4], [2, 3]]
]
The current implementation works but it is slow for list of 10 numbers
def get_all_order_combinations(nums, first=True):
if first and len(nums) == 1:
return [[[nums[0]]]]
if len(nums) == 2:
nums.sort()
return [
[[nums[0]], [nums[1]]],
[[nums[0], nums[1]]]
]
else:
all_results = []
for i in range(0, len(nums)):
temp_list = list(nums)
del temp_list[i]
current_num = nums[i]
results = get_all_order_combinations(temp_list, False)
results = [[[current_num]]+result for result in results]
for result in results:
result.sort()
if result not in all_results:
all_results.append(result)
if len(nums) >= 4:
for comb in combinations(nums, 2):
comb = list(comb)
results = get_all_order_combinations(
[n for n in nums if n not in comb]
,False
)
results = [[comb]+result for result in results]
for result in results:
result.sort()
if result not in all_results:
all_results.append(result)
return all_results
Try using the python in-built "itertools" package.
It is optimised to create combinations, which may solve your concerns with speed. Online searches will yield results on how to use it.
Here is one example:
geeksforgeeks Permutation and Combination in Python with itertools
My attempt at reproducing example 2 using itertools:
from itertools import combinations
num_list = [1, 2, 3]
output_list = []
for i in range(1, len(num_list)):
comb = combinations(num_list, i)
obtained_combinations = []
for combination in list(comb):
if i != 1:
temp_list = num_list.copy()
for selected_number in combination:
temp_list.remove(selected_number)
obtained_combinations.append([temp_list, list(combination)])
else:
obtained_combinations.append(list(combination))
output_list.append(obtained_combinations)
print(output_list)
Output:
[[[1], [2], [3]], [[[3], [1, 2]], [[2], [1, 3]], [[1], [2, 3]]]]
Related
I will start the description of the problem with an example so that the question is clear.
List of numbers: [1,2,3,4]
How can I get each successive string: [[1],[1,2],[1,2,3],[1,2,3,4],[2],[2,3],[2,3,4],[3],[3,4],[4]]
I've been trying to solve this problem for a while and managed to get [[1, 2, 3, 4], [2, 3, 4], [3, 4], [4]] with lots of useless repetitions.
list = [1,2,3,4]
i = 0
j = 0
tempList = []
sequancesList = []
while i < len(list):
while j < len(list):
tempList.append(list[j])
sequancesList.append(tempList)
j += 1
i += 1
j = i
tempList = []
def deleteDuplicates(list):
noduplist = []
for element in list:
if element not in noduplist:
noduplist.append(element)
return noduplist
finalSequancesList = deleteDuplicates(sequancesList)
print(finalSequancesList)
Here's how to do it:
list = [1,2,3,4]
sequancesList = []
for i in range(len(list)):
tmp = []
for j in range(i,len(list)):
tmp.append(list[j])
sequancesList.append(tmp[:])
print(sequancesList)
-> [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [2], [2, 3], [2, 3, 4], [3], [3, 4], [4]]
Here is a generator that does exactly that:
def iter_successive(input_list):
for i in range(len(input_list)):
for j in range(i+1,len(input_list)+1):
yield input_list[i:j]
>>> list(iter_successive(input_list))
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [2], [2, 3], [2, 3, 4], [3], [3, 4], [4]]
Comparable one-liner solution:
def iter_successive(input_list):
return (input_list[i:j] for i in range(len(input_list))
for j in range(i+1,len(input_list)+1))
Edit: As was stated in the comments, the approach below works only if the list contains whole, ascending numbers and not in other instances.
There are two ways to do this, either as a nested for-loop or a one-liner using list-comprehension. Both versions below:
Nested for-loop
nrs = list(range(1,5))
result = []
for i in nrs:
for j in range(i, max(nrs)+1):
result.append(list(range(i,j+1)))
print(result)
List-comprehension
result = [list(range(i,j+1)) for i in nrs for j in range(i, max(nrs)+1)]
print(result)
I'm trying to make a function that returns a list of n elements like the following:
factorial_list(4) → [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]
my output is [[1], [1], [2], [1], [2], [3], [1], [2], [3], [4]]
As you see I'm struggling to make the order of the inner lists. Any insights to what I should change in my code?
def factorial_list(n):
list2=[]
for i in range(1,n+1):
for j in range(1,i+1):
list2.append([j])
print(list2)
factorial_list(4)
Method 1: based on the logic of your code
def factorial_list(n):
final_list = []
for i in range(1, n+1):
temp = []
for j in range(1, i+1):
temp.append(j)
final_list.append(temp)
print(final_list)
factorial_list(4) # [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]
Method 2: a mix of for loop and list comprehensions
def factorial_list(n):
final_list = []
for i in range(1, n+1):
temp = [j for j in range(1, i+1)]
final_list.append(temp)
print(final_list)
factorial_list(4) # [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]
Method 3: using list comprehensions
def factorial_list(n):
final_list = [[j for j in range(1, i+1)] for i in range(1, n+1)]
print(final_list)
factorial_list(4) # [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]
You need to create a new list for each iteration of the first loop:
def factorial_list(n):
list2=[]
for i in range(1,n+1):
list3 = [] # <--- Create a new list for each iteration
for j in range(1,i+1):
list3.append(j)
list2.append(list3)
print(list2)
factorial_list(4)
# Output: [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]
I have a list of lists like this
[[], [1, 2, 2], [1], [2], [2], [1, 2], [1, 2], [2, 1], [2, 2]]
I want to remove all duplicates, where the order does not matter, so in the list above I need to remove [2], [1,2], and [2,1].
I thought I can do this with Counter()
from collections import Counter
counter_list = []
no_dublicates = []
for sub_list in all_subsets:
counter_dic = Counter(sub_list)
if counter_dic in counter_list:
pass
else:
no_dublicates.append(list(sub_list))
counter_list.append(counter_dic)
which works fine... but it is the slowest part of my code. I was wondering whether there is a faster way to do this?
You can convert the Counter objects to frozensets, which are hashable and can be put in a set themselves for linear savings on the in check:
from collections import Counter
counters = set()
no_duplicates = []
for sub_list in all_subsets:
c = frozenset(Counter(sub_list).items())
if c not in counters:
counters.add(c)
no_duplicates.append(list(sub_list))
Doing this with a dict comprehension also looks cool:
no_duplicates = list(
{frozenset(Counter(l).items()): l for l in all_subsets}.values())
If you don't want to use the collections module, you can also try a simple solution like this:
lsts = [[], [1, 2, 2], [1], [2], [2], [1, 2], [1, 2], [2, 1], [2, 2]]
counts = {}
for sublist in lsts:
key = tuple(sorted(sublist))
counts[key] = counts.get(key, 0) + 1
result = []
for sublist in lsts:
key = tuple(sorted(sublist))
if counts[key] == 1:
result.append(sublist)
print(result)
Which outputs:
[[], [1, 2, 2], [1], [2, 2]]
Why you are using any external module and why making it too complex when you can do it in just few lines of code:
data_=[[], [1, 2, 2], [1], [2], [2], [1, 2], [1, 2], [2, 1], [2, 2]]
dta_dict={}
for j,i in enumerate(data_):
if tuple(sorted(i)) not in dta_dict:
dta_dict[tuple(sorted(i))]=[j]
else:
dta_dict[tuple(sorted(i))].append(j)
print(dta_dict.keys())
output:
dict_keys([(1, 2), (), (1,), (2, 2), (1, 2, 2), (2,)])
if you want list instead of tutple :
print(list(map(lambda x:list(x),dta_dict.keys())))
output:
[[1, 2], [], [1], [2, 2], [1, 2, 2], [2]]
I have an array [1, 2, 3] of integer and I need to return all the possible combination of contiguous sub-arrays of this array.
[[1],[2],[3],[1,2],[2,3],[1,2,3]]
How can I handle that with python? One way would be to have 2 loops and the array itself but there should be a better way.
One line solution (I don't know what means "better way" for you)
L = [1,2,3]
[L[i:i+j] for i in range(0,len(L)) for j in range(1,len(L)-i+1)]
L=[1,2,3,4]
[L[i:i+j] for i in range(0,len(L)) for j in range(1,len(L)-i+1)]
you get,
[[1], [1, 2], [1, 2, 3], [2], [2, 3], [3]]
[[1],
[1, 2],
[1, 2, 3],
[1, 2, 3, 4],
[2],
[2, 3],
[2, 3, 4],
[3],
[3, 4],
[4]]
Simplifying the Inspector's solution:
def getAllWindows(L):
for w in range(1, len(L)+1):
for i in range(len(L)-w+1):
yield L[i:i+w]
And a solution using no loops at all:
def allSubArrays(L,L2=None):
if L2==None:
L2 = L[:-1]
if L==[]:
if L2==[]:
return []
return allSubArrays(L2,L2[:-1])
return [L]+allSubArrays(L[1:],L2)
def kwindow(L, k):
for i in range(len(L)-k+1):
yield L[i:i+k]
def getAllWindows(L):
for w in range(1, len(L)+1):
yield from kwindow(L, w)
Ouput:
In [39]: for i in getAllWindows([1,2,3]): print(i)
[1]
[2]
[3]
[1, 2]
[2, 3]
[1, 2, 3]
An itertools based approach:
import itertools
def allSubArrays(xs):
n = len(xs)
indices = list(range(n+1))
for i,j in itertools.combinations(indices,2):
yield xs[i:j]
For example:
>>> list(allSubArrays([1,2,3]))
[[1], [1, 2], [1, 2, 3], [2], [2, 3], [3]]
li=[1,2,3]
l=[]
for i in range(length(li)):
for j in range(i,len(li)+1):
if i==j: *cancelling empty sublist item*
continue
else:
subli=li[i:j]
l.append(subli)
print(l)
output:
[[1], [1, 2], [1, 2, 3], [2], [2, 3], [3]]
Let's say I have a list:
l = [0,1,2,3,4]
And I want to obtain a sequence of lists in this logic:
[[1,2,3,4],[0,1,2,3],[2,3,4],[1,2,3],[0,1,2],[3,4],[2,3],[1,2],[0,1],[0],[1],[2],[3],[4]]
That's it, sublists made of l[1:] and l[:-1]
I started by this recursive function:
l = [0,1,2,3,4]
def sublist(l):
if len(l) == 1:
return l
else:
return [sublist(l[1:]),sublist(l[:-1])]
a = [sublist(l)]
print a
But it's not really what I what as it outputs:
[[[[[[4], [3]], [[3], [2]]], [[[3], [2]], [[2], [1]]]], [[[[3], [2]], [[2], [1]]], [[[2], [1]], [[1], [0]]]]]]
import itertools
[list(itertools.combinations(l, x)) for x in range(1, len(l))]
Here's a very straightforward implementation:
def sublists_n(l, n):
subs = []
for i in range(len(l)-n+1):
subs.extend([l[i:i+n]])
return subs
def sublists(l):
subs = []
for i in range(len(l)-1,0,-1):
subs.extend(sublists_n(l,i))
return subs
>>> l = [0,1,2,3,4]
>>> sublists(l)
[[0, 1, 2, 3], [1, 2, 3, 4], [0, 1, 2], [1, 2, 3], [2, 3, 4], [0, 1], [1, 2], [2, 3], [3, 4], [0], [1], [2], [3], [4]]
[l[x:] for x in range(len(l))] + [l[:x+1] for x in range(len(l))]
Loops through l twice, but you sort of have to no matter what I think (could use zip but same thing).
A simple recursion, doesn't quite order things correctly but its simple.
def sublists(l):
right = l[1:]
left = l[:-1]
result = [right, left]
if len(l) > 2:
result.extend(sublists(right))
result.extend(sublists(left))
return result
print sublists([0,1,2,3,4])