Related
Given an integer array, find all the consecutive subsequences of alternating odd and even numbers.
Also print the total number of such subsequences.
All the subsequences should be unique.
The numbers in the list may or may not be unique.
Example:
array = [1,2,5]
output1: [[1], [1,2], [2], [2,5], [5], [1,2,5]]
output2: 6
My Code:
res = []
lst = [1,2,5]
for i in range(len(lst)-1):
res.append([lst[i]])
if abs(lst[i] - lst[i+1]) % 2 == 1:
res.append([lst[i], lst[i+1]])
print(res)
Output: [[1], [1, 2], [2], [2, 5]]
How can I get the remaining subsequences?
You care about duplicates:
def alternating_sublists(xs: list[int]) -> list[list[int]]:
results = []
for i in range(len(xs)):
if [xs[i]] not in results:
results.append([xs[i]])
for j in range(i+1, len(xs)):
if (xs[j] - xs[j-1]) % 2 != 0:
if xs[i:j+1] not in results:
results.append(xs[i:j+1])
else:
break
return results
print(list(alternating_sublists([1, 2, 5])))
print(list(alternating_sublists([1, 2, 2, 2, 1])))
print(list(alternating_sublists([1, 2, 3, 2, 3, 2, 1])))
Output:
[[1], [1, 2], [1, 2, 5], [2], [2, 5], [5]]
[[1], [1, 2], [2], [2, 1]]
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 2], [1, 2, 3, 2, 3], [1, 2, 3, 2, 3, 2], [1, 2, 3, 2, 3, 2, 1], [2], [2, 3], [2, 3, 2], [2, 3, 2, 3], [2, 3, 2, 3, 2], [2, 3, 2, 3, 2, 1], [3], [3, 2], [3, 2, 3], [3, 2, 3, 2], [3, 2, 3, 2, 1], [2, 3, 2, 1], [3, 2, 1], [2, 1]]
It's not extremely efficient (there's many lookups of lists already in the result). Depending on the application you may want a more complex data structure to save expensive 'list in large list' tests.
The basic logic is this:
each sequence has to start at some index, so try sequences starting at all possible indices for i in range(len(xs)):
the sequence with length 1 always meets your rule, so add it if it wasn't there yet
the other sequences start at index i and end at index i+1 or greater for j in range(i+1, len(xs)):
break from the loop whenever the modulo is 0 for the last two items in list you're about to add, since this sequence doesn't meet the rule, and longer ones wouldn't either.
Slightly faster and shorter, using tuples internally, but essentially the same:
def alternating_sublists2(xs: list[int]) -> list[list[int]]:
results = set()
for i in range(len(xs)):
results.add((xs[i],))
for j in range(i+1, len(xs)):
if (xs[j] - xs[j-1]) % 2 != 0:
results.add(tuple(xs[i:j+1]))
else:
break
return [list(t) for t in results]
shorter as the previous if statements are now internal to set.add()
faster because looking up tuples is faster than looking up strings, and testing membership of a set is faster than testing membership of a list
not quite as fast as you might like, since it then has to convert the result back to a list of lists, to get the result you required.
However, no guarantees on the order of the sublists in the result, so this is no good if you need the sublists in the order they are first found.
Here's a recursive solution to the problem. It iterates the elements of the list, adding the results from recursing the balance of the list when there is a change from odd to even between the current element and the next:
def odd_even(list, start=None):
result = []
for i, val in enumerate(list):
if start is None or i == 0:
if [val] not in result:
result.append([val])
if len(list) > i+1 and (list[i+1] - val) % 2 == 1:
for res in odd_even(list[i+1:], val):
if [val] + res not in result:
result = result + [[val] + res]
return result
print(odd_even([1, 2, 5]))
print(odd_even([1, 2, 2, 2, 1]))
print(odd_even([1, 2, 3, 2, 3, 2, 1]))
Output:
[[1], [1, 2], [1, 2, 5], [2], [2, 5], [5]]
[[1], [1, 2], [2], [2, 1]]
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 2], [1, 2, 3, 2, 3], [1, 2, 3, 2, 3, 2], [1, 2, 3, 2, 3, 2, 1], [2], [2, 3], [2, 3, 2], [2, 3, 2, 3], [2, 3, 2, 3, 2], [2, 3, 2, 3, 2, 1], [3], [3, 2], [3, 2, 3], [3, 2, 3, 2], [3, 2, 3, 2, 1], [2, 3, 2, 1], [3, 2, 1], [2, 1]]
Your accepted output is silly, because it's obvious that every subsequence of a "good" sequence is also "good" and there's no need to enumerate them all. Let's concentrate on finding longest alternating sequences:
def split(a):
buf = [a[0]]
for i in range(1, len(a)):
if a[i] % 2 != a[i - 1] % 2:
buf.append(a[i])
else:
yield buf
buf = [a[i]]
if buf:
yield buf
test = [1, 2, 5, 7, 3, 8, 9, 9, 10, 11]
result = list(split(test))
# [[1, 2, 5], [7], [3, 8, 9], [9, 10, 11]]
To get your expected answer, take each list from the result and generate all sublists of it. This is another, much simpler task.
This looks like a gray code sequence with additional twist:
https://en.wikipedia.org/wiki/Gray_code
Code:
import math
def powerOf2(k):
if k == 0:
return 1
else:
return 2*powerOf2(k-1)
def gray_encode(n):
return n ^ n >> 1
def count_required_sequence(lst):
n = len(lst)
sequence_nr = powerOf2(n)
results = []
results_sequence = -1
for i in range(sequence_nr):
gray = gray_encode(i)
gray_r = list("{:>010b}".format(gray))[::-1]
#print(gray_r)
count = sum(el == "1" for el in gray_r)
if count > 1:
results_sequence += 1
results.append(list())
for k in range(len(gray_r)):
if k < len(gray_r)-1:
if gray_r[k] == "1" and gray_r[k+1] == "1":
if abs(lst[k] - lst[k+1]) % 2 == 1:
results[results_sequence].append(lst[k])
results[results_sequence].append(lst[k+1])
is_there_count1 = results.count(list(set(results[results_sequence])))
results[results_sequence] = list(set(results[results_sequence]))
is_there_count = results.count(results[results_sequence])
if is_there_count > 1 or is_there_count1 > 1:
index = results.index(list(set(results[results_sequence])))
results.pop(results_sequence)
results_sequence -= 1
elif count == 1 :
results_sequence += 1
results.append(list())
pos = [index for index,value in enumerate(gray_r) if value == "1" ]
results[results_sequence].append(lst[pos[0]])
results = (list(filter(lambda a: a != [], results)))
print("results: {}".format(results))
# Driver code
if __name__ == "__main__" :
# lst = [ 1, 2, 5, 6, 7];
lst = [ 1, 2, 5 ];
count_required_sequence(lst);
Output:
results: [[1], [1, 2], [2], [2, 5], [1, 2, 5], [5]]
Change 010b to a bigger number is len(lst) is bigger then 10
gray_r = list("{:>010b}".format(gray))[::-1]
I made an implementation of Longest Increasing Subsequence (LIS) algorithm, as I see it would work, but results are totally mess.
def lis():
#D = map(int, raw_input().split())
D = [3, 2, 6, 4, 5, 1]
L = [[] for i in range(len(D))]
L[0].append(D[0])
for i in range(len(D)):
for j in range(0,i):
if D[i] > D[j]:
L[i] = L[j]
L[i].append(D[i])
print L
Returned result:
[[3], [2, 6, 4, 5], [2, 6, 4, 5], [2, 6, 4, 5], [2, 6, 4, 5], [1]]
What it should be:
[[3], [2], [2, 6], [2, 4], [2, 4, 5], [1]]
As I saw in debugger when we have:
L[i] = L[j]
Not only L[i] gets new values, but other lists on the main (L) list too...
I don't know how to avoid it. It looks that lists in Python are totally different than vectors languages from C family...
I'm fighting with this for a long time. Huge beer to someone who gonna find what is wrong :(
When you state L[i] = L[j] you do not copy the content of the list, you simply copy a reference: from now on L[i] and L[j] point to the same list and changes made through L[i] will reflect when you obtain L[j].
A simply fix is simply to copy the list:
def lis():
#D = map(int, raw_input().split())
D = [3, 2, 6, 4, 5, 1]
L = [[] for i in range(len(D))]
L[0].append(D[0])
for i in range(len(D)):
for j in range(0,i):
if D[i] > D[j]:
L[i] = list(L[j])
L[i].append(D[i])
print(L)
Now hoever your algorithm does not work anymore (it was not working in the first place nevertheless). When running your (fixed) code, you get:
>>> lis()
[[3, 3], [2], [2, 6], [2, 4], [2, 4, 5], [1]]
The 3 occurs twice in the first list, you can solve this by removing the .append before the for loop. So the final version is:
def lis():
#D = map(int, raw_input().split())
D = [3, 2, 6, 4, 5, 1]
L = [[] for i in range(len(D))] #removed the next line
for i in range(len(D)):
for j in range(0,i):
if D[i] > D[j]:
L[i] = list(L[j])
L[i].append(D[i])
print(L)
Which produces:
>>> lis()
[[3], [2], [2, 6], [2, 4], [2, 4, 5], [1]]
Note: based on your comment you use python-2.7, from python-3.x there is a method called .copy() on lists that you can call.
Important Note
The solution which is above is correct but if you try it out the result can be wrong for some instances.
For example - Longest Increasing Subsequence for numbers:
5 1 4 2 3 1 2 9 1
is
1 2 3 9
But this solution won't be on your L list returned by algorithm. There will be:
1 2 9
Max element from L list is needed. Then another element from D can be appended, so we have to add one more condition, here you go the correct code:
def lis():
#D = map(int, raw_input().split())
D = [5, 1, 4, 2, 3, 1, 2, 9, 1]
L = [[] for i in range(len(D))]
for i in range(len(D)):
for j in range(0,i):
if D[i] > D[j] and len(L[i]) < len(L[j])+1: #added condition
L[i] = list(L[j])
L[i].append(D[i])
print(L)
>>lis()
[[5], [1], [1, 4], [1, 2], [1, 2, 3], [1], [1, 2], [1, 2, 3, 9], [1]]
Given an array of numbers (e.g. [3, 5, 2]), I'm trying to generate a list of possible arrays that result from adding 1 to one entry in the array: [[4, 5, 2], [3, 6, 2], [3, 5, 3]].
I can get it done by the following, but wondering if there's a more pythonic way to get the result?
test = [3, 5, 2]
result = [t.copy() for _ in range(len(test))]
for index, _ in enumerate(result):
result[index][index] += 1
Here's how to do it with a list comprehension:
test = [3, 5, 2]
print [test[:i] + [v + 1] + test[i+1:] for i,v in enumerate(test)]
output
[[4, 5, 2], [3, 6, 2], [3, 5, 3]]
Here is another inline solution with list comprehension:
test = [3, 5, 2]
result = [[v+1 if i==j else v for j, v in enumerate(test)] for i in range(len(test))]
or, as noticed by PM 2Ring, you can exploit the fact that True == 1 and False == 0:
result = [[v + (i==j) for j, v in enumerate(test)] for i in range(len(test))]
I didn't manage to correct a code I thought it would work for sure. Any advice to make the code functional is accepted.
Expected outputs of the following code is a list containing a cyclic permuation of the list
l = [1,2,3,4] (i.e : [[4, 1, 2, 3],[3, 4, 1, 2],[2, 3, 4, 1],[1, 2, 3, 4]])
Although what I get is : [[2, 3, 4, 1]]
The code :
def cycGen(l):
L=[]
while not(l in L) :
L.append(l)
for i in range(len(l)):
if l[i] == len(l) :
l[i]=1
else :
l[i] = 1 + l[i]
return L
print(cycGen([1,2,3,4]))
Another variation of the solution is to consider the following code wich seems unfortunatly not working either :
def cycGen(l):
L=[]
for k in range(len(l)):
L.append(l)
for i in range(len(l)):
if l[i] == len(l) :
l[i]=1
else :
l[i] = 1 + l[i]
return L
Help me with your generous knowlege sharing please.
You can use collections.deque:
from collections import deque
a = [1, 2, 3, 4]
d = deque(a)
for _ in range(len(a)):
d.rotate()
print(list(d))
Which gives you the output:
[4, 1, 2, 3]
[3, 4, 1, 2]
[2, 3, 4, 1]
[1, 2, 3, 4]
As mentioned in Efficient way to shift a list in python
An easy way is just:
In [12]: x = [1,2,3,4]
In [13]: [x[i:]+x[:i] for i in range(len(x))]
Out[13]: [[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
In your first code sample, the line L.append(l) appends a "reference" (loosely speaking) to the list l to the end of L, rather than appending a copy as you seem to be expecting. Thus, when l is later modified, the reference to it contained in L is modified as well, and so when l in L is tested, l will equal the reference to itself in L, and so the loop will end. The same basic problem causes your second code sample to return multiples of the same list rather than several different lists.
To store a copy of l at the current point in time in L instead, use L.append(l[:]).
Here is an easy way:
>>> def cycGen(l):
size = len(l)
return [[l[(i+j)%size] for i in range(size)] for j in range(size)]
>>> l = [1,2,3,4]
>>> print cycGen(l)
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
You could do this using a generator too:
a = [1, 2, 3, 4]
def next_pos(max):
i = 0
while True:
for n in xrange(max):
yield n + i
i += 1
pos = next_pos(len(a))
b = []
for i in xrange(len(a)):
n = []
for j in xrange(len(a)):
m = pos.next()
if m >= len(a):
m -= len(a)
n.append(a[m])
b.append(n)
print b
output:
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
I am very much a beginner. I am trying to write a program that, given the number of elements (1-9) in the list as a parameter, will then output all permutations of the list in lexicographical order. In the program it is adding on each permutation as a list into a larger list that contains all the permutations in order. Although the program is not working as expected in general, one main problem I'm having is with this while loop In line 10, I want the list to stop compiling once the final permutation has been added to the list. For example, if my input parameter is n = 4, the last permutation/element should be [4,3,2,1]. However, when I run this program, that element is in the list three times at the end. I don't know how this is so when it should terminate that while loop once it has been added.
def ourPermutations(n):
x=list(range(1,n+1))
permList = []
permList+=[x]
xcopy = x[:]
finalPerm = xcopy[::-1]
while x != finalPerm:
istar = n-2
while x[istar] > x[istar+1]:
istar -= 1
jstar = n-1
while x[jstar] < x[istar]:
jstar -= 1
x[istar],x[jstar] = x[jstar],x[istar]
if istar+1 == n-1:
x = x[:]
else:
a = x[istar+1:]
a = a[::-1]
x = x[:istar+1] + a
permList += [x]
return permList
That is my main question; however, this program is still missing elements when I run it. It isn't quite working, so if you see a spot where something is obviously wrong, feel free to tell me that particular line is what is causing my problems. If it helps, this is based on this identical (and correct) version written in Mathematica 8:
ourpermutations[n_] := (
ourlist = {x=Range[1,n]};
While[
x != Reverse[Range[1,n]],
istar = n-1;
While[x[[istar]] > x[[istar+1, istar--];
jstar = n; While[x[[jstar]] < x[[istar]], jstar--];
x[[{istar, jstar}]] = x[[{jstar, istar}]];
AppendTo[ourlist, x = Join[Take[x,istar], Reverse[Drop[x,istar]]]]
];
ourlist
)
So this is what my Python code should be doing; I just can't get it to do so just yet. Thanks for any of your time and effort.
It looks like you're running into a problem because you aren't copying x soon enough and so you're sometimes modifying x after it's been added to permList. This can be solved by adding x = x[:] at the start of your while loop:
def ourPermutations(n):
x=list(range(1,n+1))
permList = []
permList+=[x]
xcopy = x[:]
finalPerm = xcopy[::-1]
while x != finalPerm:
x = x[:]
istar = n-2
while x[istar] > x[istar+1]:
istar -= 1
jstar = n-1
while x[jstar] < x[istar]:
jstar -= 1
x[istar],x[jstar] = x[jstar],x[istar]
if istar+1 == n-1:
x = x[:]
else:
a = x[istar+1:]
a = a[::-1]
x = x[:istar+1] + a
permList += [x]
return permList
>>> ourPermutations(3)
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
>>> ourPermutations(4)
[[1, 2, 3, 4], [1, 2, 4, 3], [1, 3, 2, 4], [1, 3, 4, 2], [1, 4, 2, 3], [1, 4, 3, 2], [2, 1, 3, 4], [2, 1, 4, 3], [2, 3, 1, 4], [2, 3, 4, 1], [2, 4, 1, 3], [2, 4, 3, 1], [3, 1, 2, 4], [3, 1, 4, 2], [3, 2, 1, 4], [3, 2, 4, 1], [3, 4, 1, 2], [3, 4, 2, 1], [
4, 1, 2, 3], [4, 1, 3, 2], [4, 2, 1, 3], [4, 2, 3, 1], [4, 3, 1, 2], [4, 3, 2, 1]]
A slightly more "pythonic" version might look like:
def our_permutations(n):
x = list(range(1, n+1))
perm_list = [x]
final_perm = x[::-1]
while x != final_perm:
x = x[:]
istar = n-2
while x[istar] > x[istar+1]:
istar -= 1
jstar = n-1
while x[jstar] < x[istar]:
jstar -= 1
x[istar],x[jstar] = x[jstar],x[istar]
if istar+1 != n-1:
a = x[istar+1:]
a = a[::-1]
x = x[:istar+1] + a
perm_list += [x]
return perm_list
Checking these functions against itertools.permutation shows that they produce the same answers, so it looks like your algorithm was correct except for that small mistake.