I created a code using itertools combination. The code snippet is below. What is the Big O complexity? Is it O(n!)?
a_list =[ 'A', 'B','C' ]
all_combinations = []
for r in range(len(a_list) + 1):
combinations_object = itertools.combinations(a_list, r)
combinations_list = list(combinations_object)
all_combinations += combinations_list
print(all_combinations)
[(), (A,), (B,), (C,), (A, B), (A, C), (B, C), (A, B, B)]
Thank you!
Getting all combinations of a list is O(n!). Since you're doing that n times to get combinations with different values of r, the whole algorithm is O(n*n!).
Related
I got stuck coming up with an algorithm and I don't know what to do now.
I need to get from a to d but only by scrolling through these lists:
[e, d]
[a, b, c]
[d, a]
[a, b]
[a, e, b]
This is of course a simple example and the solution is:
[a → d] // 3rd line
[a → e → d] // 5th line + 1st line
[a → b → e → d] // 2nd + 5th + 1st line
But I have to solve it in Python.
I came up with two ways to solve this, the first was using for-loops, but the loops started repeating and got very time consuming, so I went with idea number 2.
I was thinking of creating a list of all possible variants that start with a and end with d. And then check if this is possible in our specified lists.
from itertools import permutations
lst = ['a', 'b', 'c', 'd', 'e']
x = 'a'
y = 'd'
for i in range(1, len(lst)):
perm = permutations(lst, i+1)
for j in list(perm):
if (j[0] == x) and (j[-1] == y):
print(j)
But then somehow I got stuck and I don't know what to do now. Could someone please give me a hint? Or am I going about this all wrong?
edit:
I'm trying to find all the paths and print them.
This is a graph problem where the lists are undirected edges between the nodes. For example:
[a, b, c]
means that there are undirected edges from a to b and c, from b to a and c, and from c to a and b. Of course, a -- b, also means b -- a. I have repeated the edges above only for clarity.
So, what you want to do is to create an adjacency list that represents all of these edges and apply backtracking since you want all the possible paths from source to target.
Here is some code that shows you the idea:
adj_list = collections.defaultdict(set)
for row in rows:
for i, el in enumerate(row):
for j in range(i+1, len(row):
adj_list[el].add(row[j])
adj_list[row[j]].add(el)
def backtrack(node, adj_list, seen, partial_res, res):
if node == target:
res.append(partial_res[:])
for neighbor in adj_list[node]:
if neighbor in seen: continue
seen.add(neighbor)
partial_res.append(neighbor)
backtrack(neighbor, adj_list, seen, partial_res, res)
partial_res.pop()
seen.remove(neighbor)
res = []
backtrack(start, adj_list, set(), [], res)
print(res)
I haven't run this. But the code should give an idea of how backtracking works. It's a dfs where you check each possible path and keep track of the edges that you traveled. If it leads to destination, you save a copy of it in your final results.
Please note that this algorithm only visit each node once in each path.
I am using sympy to do some calculations, but I need to manipulate results of multiplications using rules I have to define. Let us suppose I have
a, b, c, d = symbols('a b c d', commutative=False)
res = a*b + b*c + c*d
I was wondering how can I write a function which takes res and gives a list of this kind
[[a,b],[b,c],[c,d]]
since every time I try to perform operations like list(res) python throws the exception Mul (Add) object is not iterable. Thanks in advance
There is no function for this already but you can make one like this:
def factors(expr):
result = []
for term in Add.make_args(expr):
flat_factors = []
for factor in Mul.make_args(term):
symbol, power = factor.as_base_exp()
flat_factors += [symbol] * power
result.append(flat_factors)
return result
That gives:
In [74]: factors(a*b + b*c + c*d)
Out[74]: [[a, b], [b, c], [c, d]]
In [75]: factors(a**2*b + a*b**2)
Out[75]: [[a, b, b], [a, a, b]]
This is a way:
[x.as_ordered_factors() for x in res.as_ordered_terms()]
No sure, but do you wanna do something like this?
res = 'a*b + b*c + c*d'
def list_func(res):
list1 = res.split('+')
return ([item.split('*') for item in list1])
print(list_func(res))
I need help writing some Python code that input is a list A that represents a set and whose output is a list of the subsets of A that have cardinality of 2. I want to do this using an import, my professor wants me to understand where the numbers come from.
For instance:
if A = [a, b, c], then
listPairs(A) = [[a, b], [a, c], [b, c]].
Try itertools.combinations. The following returns all subsequences of length 2 of A.
import itertools
[set(x) for x in itertools.combinations(A, 2)]
Examples:
# AB AC AD BC BD CD
[set(x) for x in itertools.combinations('ABCD', 2)]
# 012 013 023 123
[set(x) for x in itertools.combinations(range(4), 3)]
This is the syntax for the functional equivalent:
list(map(set, itertools.combinations(A, 2)))
You are essentially after the most standard combinations function. As
already pointed out, this can be done easily with itertools.combinations, or you can implement it yourself with recursion:
def combos(l, n):
if n == 1:
return [[e] for e in l]
cs = []
for i, e in enumerate(l):
for c in combos(l[i+1:], n-1):
cs.append([e] + c)
return cs
and a test demonstrates its functionality:
>>> combos(['a', 'b', 'c'], 2)
[['a', 'b'], ['a', 'c'], ['b', 'c']]
I am trying to generate all permuations of a set of items and the my R needs to be larger than the size of the set of items
Here is an example :
itertools.permutations ("ABC", 4)
this always returns 0 items as R > N.
I want this
[A, A, A, A]
[A, A, A, B]
[A, A, B, A]
[A, B, A, A]
...
How can I achieve this?
You don't seem to want the permutation, but the Cartesian product:
itertools.product("ABC", repeat=4)
https://docs.python.org/3/library/itertools.html#itertools.product
I need to store in a list the indexes of those values in 3 lists which exceed a given maximum limit. This is what I got:
# Data lists.
a = [3,4,5,12,6,8,78,5,6]
b = [6,4,1,2,8,784,43,6,2]
c = [8,4,32,6,1,7,2,9,23]
# Maximum limit.
max_limit = 20.
# Store indexes in list.
indexes = []
for i, a_elem in enumerate(a):
if a_elem > max_limit or b[i] > max_limit or c[i] > max_limit:
indexes.append(i)
This works but I find it quite ugly. How can I make it more elegant/pythonic?
You could replace your for loop with:
indexes = []
for i, triplet in enumerate(zip(a, b, c)):
if any(e > max_limit for e in triplet):
indexes.append(i)
... which you could then reduce to a list comprehension:
indexes = [i for i, t in enumerate(zip(a, b, c)) if any(e > max_limit for e in t)]
... although that seems a little unwieldy to me - this is really about personal taste, but I prefer to keep listcomps simple; the three-line for loop is clearer in my opinion.
As pointed out by user2357112, you can reduce the apparent complexity of the list comprehension with max():
indexes = [i for i, t in enumerate(zip(a, b, c)) if max(t) > max_limit]
... although this won't short-circuit in the same way that the any() version (and your own code) does, so will probably be slightly slower.
You could try
if max(a_elem, b[i], c[i]) > max_limit:
indexes.append(i)
The logic here is finding out if any one of these three values needs to be greater than max_limit. If the greatest element of these three is greater than max_limit, your condition is satisfied.
I like the exceeders = line best myself
import collections
# Data lists.
a = [3,4,5,12,6,8,78,5,6]
b = [6,4,1,2,8,784,43,6,2]
c = [8,4,32,6,1,7,2,9,23]
Triad = collections.namedtuple('Triad', 'a b c')
triads = [Triad(*args) for args in zip(a, b, c)]
triads = [t for t in zip(a, b, c)] # if you don't need namedtuple
# Maximum limit.
max_limit = 20.
# Store indexes in list.
indexes = [for i, t in enumerate(triads) if max(t) > max_limit]
print indexes
# store the bad triads themselves in a list for
# greater pythonic
exceeders = [t for t in triads if max(t) > max_limit]
print exceeder
As I commented above, using parallel arrays to represent data that are related makes simple code much less simple than it need be.
added in response to comment
Perhaps I gave you too many alternatives, so I shall give only one way instead. One feature that all of the answers have in common is that they fuse the separate "data lists" into rows using zip:
triads = [t for t in zip(a, b, c)]
exceeders = [t for t in triads if max(t) > max_limit]
That's it: two lines. The important point is that storing the index of anything in a list is a C-style way of doing things and you asked for a Pythonic way. Keeping a list of indices means that anytime you want to do something with the data at that index, you have to do an indirection. After those two lines execute, exceeders has the value:
[(5, 1, 32), (8, 784, 7), (78, 43, 2), (6, 2, 23)]
Where each member of the list has the "column" of your three data rows that was found to exceed your limit.
Now you might say "but I really wanted the indices instead". If that is so, there is another part of your problem which you didn't show us which also relies on list indexing. If so, you are still doing things in a C/C++/Java way and "Pythonic" will remain evasive.
>>> maximums = map(max, zip(a, b, c))
>>> [i for i, num in enumerate(maximums) if num > max_limit]
[2, 5, 6, 8]
Old answer
Previously, I posted the mess below. The list comp above is much more manageable.
>>> next(zip(*filter(lambda i: i[1] > max_limit, enumerate(map(max, zip(a, b, c))))))
(2, 5, 6, 8)
m = lambda l: [i for i, e in enumerate(l) if e>max_limit]
indexes = sorted(set(m(a) + m(b) + m(c)))