We have to accept a list and find the subsequent from the list such that number in subsequence are in increasing order.
Find sum of each subsequence
return maximum sum
For example
Input=[1, 4,2]
Possible subsequence will be [1][4][2][1,4][1,2]
Here [4,2] will not come as 4 is greater. And order should not change. Means first position elements if it comes in sublist it should be first
Sum of each subsequence will be 1,4,2,5,3
Output will be 5.
What will be your logic to solve it?
You can use itertools.combinations and itertools.chain to do this easily
>>> from itertools import combinations, chain
>>> Input=[1, 4,2]
>>> max(map(sum, (filter(lambda x: sorted(x) == list(x), chain(*[combinations(Input, i) for i in range(1, len(Input)+1)])))))
5
Explanation
>>> possibilities = chain(*[combinations(Input, i) for i in range(1, len(Input)+1)])
>>> filtered_possibilities = filter(lambda x: sorted(x) == list(x), possibilities)
>>> sum_of_each_possibility = map(sum, filtered_possibilities)
>>> max_sum = max(sum_of_each_possibility)
>>> print (max_sum)
5
You can break down the question into three steps:
1) Find the power_set(all sub lists) of list.
2) Filter out unwanted list (list with decreasing order).
3) Find the max sum.
Step1:
def powerset(s):
x = len(s)
res=[]
for i in range(1 << x):
res.append([s[j] for j in range(x) if (i & (1 << j))])
return res
lst=[1,4,2]
res=powerset(lst)
Step 2&3:
def max_sub(lsts):
max_out=0
def helper(lsts): #Step2: to filter out decreasing lists.
if lsts==[]:
return False
else:
for i in range(len(lsts)-1):
if lsts[i]>lsts[i+1]:
return False
return True
filtered_lst=list(filter(lambda x:helper(x),lsts))
for lst in filtered_lst:
max_out=max(max_out,sum(lst)) #step3: Find out the max sub list sum.
return max_out
print(max_sub(res))
Result:
5
Drako already mentioned, that this is not free coding service. Show some effort yourself and tell us, what you already tried and how it didn't work. also provide output to help us analyze the problem. I'll help anyway; also welcome to StackOverflow.
What you are looking for is a "power set". An exhaustive set M of sets s, where each s is a subset of M and there is in fact no subset of M which is not already contained in a s. As sets are unordered by definition, you don't have to care about duplicates because of different ordering. Looking at this question
There is a nice answer to get the power set of a given set. Assuming your input list/set/iterable is i, you can use the following code to get the power set list.
from itertools import chain, combinations
def get_power_set(i):
i.sort() # Sorted input --> sorted output
ps_iterable = chain.from_iterable(combinations(i, r) for r in range(len(i)+1))
return list(ps_iterable)
def get_highest_sum(input_list):
maximum = 0
for s in input_list:
sum_of_set = sum(s)
if sum_of_set > maximum:
maximum = sum_of_set
return maximum
i = [1,2,3] # Assign your input list here
power_set = get_power_set(i)
highest_sum = get_highest_sum(power_set)
print(power_set)
# >>> [(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
print("Highest sum is {}".format(highest_sum))
# >>> 6
Related
This question already has answers here:
How do I iterate through two lists in parallel?
(8 answers)
Closed 2 years ago.
How can I include two variables in the same for loop?
t1 = [a list of integers, strings and lists]
t2 = [another list of integers, strings and lists]
def f(t): #a function that will read lists "t1" and "t2" and return all elements that are identical
for i in range(len(t1)) and for j in range(len(t2)):
...
If you want the effect of a nested for loop, use:
import itertools
for i, j in itertools.product(range(x), range(y)):
# Stuff...
If you just want to loop simultaneously, use:
for i, j in zip(range(x), range(y)):
# Stuff...
Note that if x and y are not the same length, zip will truncate to the shortest list. As #abarnert pointed out, if you don't want to truncate to the shortest list, you could use itertools.zip_longest.
UPDATE
Based on the request for "a function that will read lists "t1" and "t2" and return all elements that are identical", I don't think the OP wants zip or product. I think they want a set:
def equal_elements(t1, t2):
return list(set(t1).intersection(set(t2)))
# You could also do
# return list(set(t1) & set(t2))
The intersection method of a set will return all the elements common to it and another set (Note that if your lists contains other lists, you might want to convert the inner lists to tuples first so that they are hashable; otherwise the call to set will fail.). The list function then turns the set back into a list.
UPDATE 2
OR, the OP might want elements that are identical in the same position in the lists. In this case, zip would be most appropriate, and the fact that it truncates to the shortest list is what you would want (since it is impossible for there to be the same element at index 9 when one of the lists is only 5 elements long). If that is what you want, go with this:
def equal_elements(t1, t2):
return [x for x, y in zip(t1, t2) if x == y]
This will return a list containing only the elements that are the same and in the same position in the lists.
There's two possible questions here: how can you iterate over those variables simultaneously, or how can you loop over their combination.
Fortunately, there's simple answers to both. First case, you want to use zip.
x = [1, 2, 3]
y = [4, 5, 6]
for i, j in zip(x, y):
print(str(i) + " / " + str(j))
will output
1 / 4
2 / 5
3 / 6
Remember that you can put any iterable in zip, so you could just as easily write your exmple like:
for i, j in zip(range(x), range(y)):
# do work here.
Actually, just realised that won't work. It would only iterate until the smaller range ran out. In which case, it sounds like you want to iterate over the combination of loops.
In the other case, you just want a nested loop.
for i in x:
for j in y:
print(str(i) + " / " + str(j))
gives you
1 / 4
1 / 5
1 / 6
2 / 4
2 / 5
...
You can also do this as a list comprehension.
[str(i) + " / " + str(j) for i in range(x) for j in range(y)]
Any reason you can't use a nested for loop?
for i in range(x):
for j in range(y):
#code that uses i and j
for (i,j) in [(i,j) for i in range(x) for j in range(y)]
should do it.
If you really just have lock-step iteration over a range, you can do it one of several ways:
for i in range(x):
j = i
…
# or
for i, j in enumerate(range(x)):
…
# or
for i, j in ((i,i) for i in range(x)):
…
All of the above are equivalent to for i, j in zip(range(x), range(y)) if x <= y.
If you want a nested loop and you only have two iterables, just use a nested loop:
for i in range(x):
for i in range(y):
…
If you have more than two iterables, use itertools.product.
Finally, if you want lock-step iteration up to x and then to continue to y, you have to decide what the rest of the x values should be.
for i, j in itertools.zip_longest(range(x), range(y), fillvalue=float('nan')):
…
# or
for i in range(min(x,y)):
j = i
…
for i in range(min(x,y), max(x,y)):
j = float('nan')
…
"Python 3."
Add 2 vars with for loop using zip and range; Returning a list.
Note: Will only run till smallest range ends.
>>>a=[g+h for g,h in zip(range(10), range(10))]
>>>a
>>>[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
For your use case, it may be easier to utilize a while loop.
t1 = [137, 42]
t2 = ["Hello", "world"]
i = 0
j = 0
while i < len(t1) and j < len(t2):
print t1[i], t2[j]
i += 1
j += 1
# 137 Hello
# 42 world
As a caveat, this approach will truncate to the length of your shortest list.
I think you are looking for nested loops.
Example (based on your edit):
t1=[1,2,'Hello',(1,2),999,1.23]
t2=[1,'Hello',(1,2),999]
t3=[]
for it1, e1 in enumerate(t1):
for it2, e2 in enumerate(t2):
if e1==e2:
t3.append((it1,it2,e1))
# t3=[(0, 0, 1), (2, 1, 'Hello'), (3, 2, (1, 2)), (4, 3, 999)]
Which can be reduced to a single comprehension:
[(it1,it2,e1) for it1, e1 in enumerate(t1) for it2, e2 in enumerate(t2) if e1==e2]
But to find the common elements, you can just do:
print set(t1) & set(t2)
# set([(1, 2), 1, 'Hello', 999])
If your list contains non-hashable objects (like other lists, dicts) use a frozen set:
from collections import Iterable
s1=set(frozenset(e1) if isinstance(e1,Iterable) else e1 for e1 in t1)
s2=set(frozenset(e2) if isinstance(e2,Iterable) else e2 for e2 in t2)
print s1 & s2
I have a list of 50 numbers, [0,1,2,...49] and I would like to create a list of tuples without duplicates, where i define (a,b) to be a duplicate of (b,a). Similarly, I do not want tuples of the form (a,a).
I have this:
pairs = set([])
mylist = range(0,50)
for i in mylist:
for j in mylist:
pairs.update([(i,j)])
set((a,b) if a<=b else (b,a) for a,b in pairs)
print len(pairs)
>>> 2500
I get 2500 whereas I expect to get, i believe, 1225 (n(n-1)/2).
What is wrong?
You want all combinations. Python provides a module, itertools, with all sorts of combinatorial utilities like this. Where you can, I would stick with using itertool, it almost certainly faster and more memory efficient than anything you would cook up yourself. It is also battle-tested. You should not reinvent the wheel.
>>> import itertools
>>> combs = list(itertools.combinations(range(50),2))
>>> len(combs)
1225
>>>
However, as others have noted, in the case where you have a sequence (i.e. something indexable) such as a list, and you want N choose k, where k=2 the above could simply be implemented by a nested for-loop over the indices, taking care to generate your indices intelligently:
>>> result = []
>>> for i in range(len(numbers)):
... for j in range(i + 1, len(numbers)):
... result.append((numbers[i], numbers[j]))
...
>>> len(result)
1225
However, itertool.combinations takes any iterable, and also takes a second argument, r which deals with cases where k can be something like 7, (and you don't want to write a staircase).
Your approach essentially takes the cartesian product, and then filters. This is inefficient, but if you wanted to do that, the best way is to use frozensets:
>>> combinations = set()
>>> for i in numbers:
... for j in numbers:
... if i != j:
... combinations.add(frozenset([i,j]))
...
>>> len(combinations)
1225
And one more pass to make things tuples:
>>> combinations = [tuple(fz) for fz in combinations]
Try This,
pairs = set([])
mylist = range(0,50)
for i in mylist:
for j in mylist:
if (i < j):
pairs.append([(i,j)])
print len(pairs)
problem in your code snippet is that you filter out unwanted values but you don't assign back to pairs so the length is the same... also: this formula yields the wrong result because it considers (20,20) as valid for instance.
But you should just create the proper list at once:
pairs = set()
for i in range(0,50):
for j in range(i+1,50):
pairs.add((i,j))
print (len(pairs))
result:
1225
With that method you don't even need a set since it's guaranteed that you don't have duplicates in the first place:
pairs = []
for i in range(0,50):
for j in range(i+1,50):
pairs.append((i,j))
or using list comprehension:
pairs = [(i,j) for i in range(0,50) for j in range(i+1,50)]
Suppose we have a variable sets and suppose each variable gets few values from sets . So . Now there is a function . How can I sum up on all possible values of to on ?
For example if and and and then I am looking for:
*The size of can change. So the size of it is also changing. I didn't want to write in a complex form but actually I am adding up multiple functions which each has their own variable set.
You can use itertools.product
>>> from itertools import product
>>> V = [[1,2],[3,4,5]]
>>> summ = 0
>>> for x in product(*V):
print x
# or call some function : summ += func(*x)
...
(1, 3)
(1, 4)
(1, 5)
(2, 3)
(2, 4)
(2, 5)
You can use a list to represent the sets. So V is a list of lists.
V = [[1,2],[3,4,5]]
r = [[]]
for v in V:
r = [ i + [y] for y in v for i in r ]
# at this point, r contains the inputs for your functions
sum = 0
for domain in r:
sum += function(domain)
All you have to do is define your function to accept a list. In your example, it would be this:
def function(l):
return l[0] * l[1]
I want to build a recursive function that finds all the subsets of size 'k' of a given list with length n>=k>=0 and returns a list of those subsets.
example:
if the input list is [1,2,3,4] and k = 2 then the function will return
[[4,3],[2,4],[2,3],[1,4],[1,3],[1,2]]
notice that different arrangments of list is considered to be the same list.
I think that this kind of recursion should work:
return [lst[0]] + choose_sets(lst[1:],k-1) ¬¬and¬¬ choose_sets(lst[1:],k)
where choose_sets(lst,k) is the function.
Meaning:
input : [1,2,3,4] , k=3
calls:
[1] + [2,3,4],k=2 and [2,3,4], k=3
and so on...
can anyone guide me as to how I should call those 2 recursive calls 'at the same time' ?
and what should my 'exiting term' be?
Thanks.
Suppose you have a list of size n and you need all subsets of size k.
This is basically the same as:
For each element of the list,
create a new list without the element,
in the new list, find all the subsets of size k-1 (this is the recursive call),
and add the remove element to all the lists.
Now... this solution will have repetitions, for example, in the example you gave, you'll get both [4, 1] and [1, 4]. But it can be changed a little so that it will not create duplicate results.
edit
to handle duplications
def choose_sets(l, k):
if k == 0:
return [[]]
if len(l) == 0:
return []
l2 = l[1:]
subsets = choose_sets(l2, k-1)
for s in subsets:
s.append(l[0])
return subsets+ choose_sets(l2, k)
b = []
def abc(a,k):
if len(a)==k:
b.append(a)
return b
b.extend([a[:k-1]+[i] for i in a[k-1:]])
return abc(a[1:],k)
print abc([1,2,3,4,5],2)
Context - developing algorithm to determine loop flows in a power flow network.
Issue:
I have a list of lists, each list represents a loop within the network determined via my algorithm. Unfortunately, the algorithm will also pick up the reversed duplicates.
i.e.
L1 = [a, b, c, -d, -a]
L2 = [a, d, c, -b, -a]
(Please note that c should not be negative, it is correct as written due to the structure of the network and defined flows)
Now these two loops are equivalent, simply following the reverse structure throughout the network.
I wish to retain L1, whilst discarding L2 from the list of lists.
Thus if I have a list of 6 loops, of which 3 are reversed duplicates I wish to retain all three.
Additionally, The loop does not have to follow the format specified above. It can be shorter, longer, and the sign structure (e.g. pos pos pos neg neg) will not occur in all instances.
I have been attempting to sort this by reversing the list and comparing the absolute values.
I am completely stumped and any assistance would be appreciated.
Based upon some of the code provided by mgibson I was able to create the following.
def Check_Dup(Loops):
Act = []
while Loops:
L = Loops.pop()
Act.append(L)
Loops = Popper(Loops, L)
return Act
def Popper(Loops, L):
for loop in Loops:
Rev = loop[::-1]
if all (abs(x) == abs(y) for x, y in zip(loop_check, Rev)):
Loops.remove(loop)
return Loops
This code should run until there are no loops left discarding the duplicates each time. I'm accepting mgibsons answers as it provided the necessary keys to create the solution
I'm not sure I get your question, but reversing a list is easy:
a = [1,2]
a_rev = a[::-1] #new list -- if you just want an iterator, reversed(a) also works.
To compare the absolute values of a and a_rev:
all( abs(x) == abs(y) for x,y in zip(a,a_rev) )
which can be simplified to:
all( abs(x) == abs(y) for x,y in zip(a,reversed(a)) )
Now, in order to make this as efficient as possible, I would first sort the arrays based on the absolute value:
your_list_of_lists.sort(key = lambda x : map(abs,x) )
Now you know that if two lists are going to be equal, they have to be adjacent in the list and you can just pull that out using enumerate:
def cmp_list(x,y):
return True if x == y else all( abs(a) == abs(b) for a,b in zip(a,b) )
duplicate_idx = [ idx for idx,val in enumerate(your_list_of_lists[1:])
if cmp_list(val,your_list_of_lists[idx]) ]
#now remove duplicates:
for idx in reversed(duplicate_idx):
_ = your_list_of_lists.pop(idx)
If your (sub) lists are either strictly increasing or strictly decreasing, this becomes MUCH simpler.
lists = list(set( tuple(sorted(x)) for x in your_list_of_lists ) )
I don't see how they can be equivalent if you have c in both directions - one of them must be -c
>>> a,b,c,d = range(1,5)
>>> L1 = [a, b, c, -d, -a]
>>> L2 = [a, d, -c, -b, -a]
>>> L1 == [-x for x in reversed(L2)]
True
now you can write a function to collapse those two loops into a single value
>>> def normalise(loop):
... return min(loop, [-x for x in reversed(L2)])
...
>>> normalise(L1)
[1, 2, 3, -4, -1]
>>> normalise(L2)
[1, 2, 3, -4, -1]
A good way to eliminate duplicates is to use a set, we just need to convert the lists to tuples
>>> L=[L1, L2]
>>> set(tuple(normalise(loop)) for loop in L)
set([(1, 2, 3, -4, -1)])
[pair[0] for pair in frozenset(sorted( (c,negReversed(c)) ) for c in cycles)]
Where:
def negReversed(list):
return tuple(-x for x in list[::-1])
and where cycles must be tuples.
This takes each cycle, computes its duplicate, and sorts them (putting them in a pair that are canonically equivalent). The set frozenset(...) uniquifies any duplicates. Then you extract the canonical element (in this case I arbitrarily chose it to be pair[0]).
Keep in mind that your algorithm might be returning cycles starting in arbitrary places. If this is the case (i.e. your algorithm might return either [1,2,-3] or [-3,1,2]), then you need to consider these as equivalent necklaces
There are many ways to canonicalize necklaces. The above way is less efficient because we don't care about canonicalizing the necklace directly: we just treat the entire equivalence class as the canonical element, by turning each cycle (a,b,c,d,e) into {(a,b,c,d,e), (e,a,b,c,d), (d,e,a,b,c), (c,d,e,a,b), (b,c,d,e,a)}. In your case since you consider negatives to be equivalent, you would turn each cycle into {(a,b,c,d,e), (e,a,b,c,d), (d,e,a,b,c), (c,d,e,a,b), (b,c,d,e,a), (-a,-b,-c,-d,-e), (-e,-a,-b,-c,-d), (-d,-e,-a,-b,-c), (-c,-d,-e,-a,-b), (-b,-c,-d,-e,-a)}. Make sure to use frozenset for performance, as set is not hashable:
eqClass.pop() for eqClass in {frozenset(eqClass(c)) for c in cycles}
where:
def eqClass(cycle):
for rotation in rotations(cycle):
yield rotation
yield (-x for x in rotation)
where rotation is something like Efficient way to shift a list in python but yields a tuple