Reversing order in incrementing digits - python

I have a list of numbers, and I'm trying to do the following in a way as efficient as possible.
For each consecutively incrementing chunk in the list I have to reverse its order.
This is my attempt so far:
l = []
l_ = []
i = 0
while i <= len(a)-1:
if a[i] < a[i+1]:
l_= l_ + [a[i]]
else:
l = l_ + [a[i]]
l_ = []
i = i + 1
I'd appreciate any guidance or other approaches.
So, for the following list:
a = [1,5,7,3,2,5,4,45,1,5,10,12]
I would like to obtain:
[7,5,1,3,5,2,45,4,12,10,5,1]

Try this:
(with fixes from #Scott Boston and #myrmica)
nums = [1, 3, 5, 4, 6, 8, 9, 7, 2, 4] # sample input
chunk = [] # keep track of chunks
output = [] # output list
for i in nums:
if chunk and i < chunk[-1]:
output.extend(chunk[::-1]) # add reversed chunk to output
chunk[:] = [i] # clear chunk
else:
chunk.append(i) # add to chunk
output.extend(chunk[::-1]) # empty leftover chunk
print(output)

with comprehension lists :
a = [1,5,7,3,2,5,4,45,1,5,10,12]
split=[0]+[i for i in range(1,len(a)) if a[i-1]>a[i]]+[len(a)]
#[0, 3, 4, 6, 8, 12]
chunks=[list(reversed(a[i:j])) for i,j in zip(split[:-1],split[1:])]
#[[7, 5, 1], [3], [5, 2], [45, 4], [12, 10, 5, 1]]
print(sum(chunks,[]))
#[7, 5, 1, 3, 5, 2, 45, 4, 12, 10, 5, 1]

Related

Why the 'list' is resulting empty after getting appended with a deleted list?

Here is my code, Could anyone please help me why the 'long_band' resulted in empty list?
Expected output: [[9,10],[0,1,2,3,4,5,6,7],[18],[12]]
Code begins here:
arr = [1, 9, 3, 0, 18, 5, 2, 4, 10, 7, 12, 6]
len1 = len(arr)
long_band = list()
chain = list()
def band(i):
chain.append(i)
j = i+1
if j in arr:
band(j)
else:
#print(chain)
#print(long_band)
long_band.append([chain])
#print(long_band)
del chain[:]
def isHead(n):
x = n-1
if x in arr:
None
else:
band(n)
for i in range(len1):
isHead(arr[i])
print(long_band)
The immediate problem is this:
long_band.append([chain])
del chain[:]
You're appending the chain object to the list, and then immediately clear it. This also clears the object in the list, because there's only one object. Appending it to a list doesn't create a copy of it.
The bigger problem is that your algorithm is way overcomplicated. Here's a much simpler approach:
>>> arr = [1, 9, 3, 0, 18, 5, 2, 4, 10, 7, 12, 6]
>>> arr.sort()
>>> res = [arr[0:1]]
>>> for i, j in zip(arr, arr[1:]):
... if i != j - 1:
... res.append([])
... res[-1].append(j)
...
>>> res
[[0, 1, 2, 3, 4, 5, 6, 7], [9, 10], [12], [18]]
arr = [1, 9, 3, 0, 18, 5, 2, 4, 10, 7, 12, 6]
len1 = len(arr)
long_band = list()
chain = list()
def band(i):
chain.append(i)
j = i+1
if j in arr:
band(j)
else:
long_band.append(chain[:])
del chain[:]
def isHead(n):
x = n-1
if x in arr:
None
else:
band(n)
def FindMaxLen(long_band):
maxLength = max(len(x) for x in long_band)
print(maxLength)
for i in range(len1):
isHead(arr[i])
print(long_band)
FindMaxLen(long_band)

Find pairs of consecutive integers in array PYTHON

I'm trying to loop through an array and return an integer every time it shows up twice --- I've been trying to figure this out for days and really need some help
example:
input = [3, 4, 4, 4, 5, 6, 6, 5, 4, 4]
result = [4,6,4]
result=[]
def findPairs(input):
i = 0
while i < len(input):
for j in input:
if input[1]==input[2]:
result.append(j)
i += 1
print(result)
print (findPairs(input))
In response to the more recent clarifications:
def find_pairs(xs):
result = []
i = 0
while i < len(xs) - 1:
if xs[i] == xs[i + 1]:
result.append(xs[i])
i += 1
i += 1
return result
Testing:
>>> xs = [3, 4, 4, 4, 5, 6, 6, 5, 4, 4]
>>> find_pairs(xs)
[4, 6, 4]
Update: Minor off-by-one bug fix.
Try this method with list comprehensions -
import itertools
inp = [3, 4, 4, 4, 5, 6, 6, 5, 4, 4]
l = [i for i in zip(inp, inp[1:]) if i[0]==i[1]] #first get consecutive repeats
out = [k[0] for k, g in itertools.groupby(l)] #sequential grouping of repeated groups to count more than 2 occurances as a single one as well
print(out)
[4, 6, 4]

How to split a nested list of ints into a a list

lst = [[1, 5],
[2, 2]
this is my nested list, I need to make a list of the points of this:
output = [[1, 5, 2, 2]
here is my attempt at this which works for this case but fails if I have an example where the row length is 6 or greater than 4
new_lst = []
for x in range(len(lst)):
for y in range(0, len(lst[x]), 2):
new_lst.append([lst[x][y],lst[x][y+1]])
counter_a = 0
counter_b = 1
output = []
while counter_b - 4 <= len(lst):
output.append(new_lst[counter_a] + new_lst[counter_a + 2])
output.append(new_lst[counter_b] + new_lst[counter_b + 2])
counter_a += 4
counter_b += 4
print(output)
How about this? This is general for all lists with size nxm where n and m are even numbers. The logic is to iterate with a step of 2 in both row and column, then take the block of 2x2 elements and append it to the output list.
lst = [[1, 6, 5, 6],
[2, 5, 6, 8],
[7, 2, 8, 1],
[4, 4, 7, 3]]
output = []
for j in range(0, len(lst), 2):
for i in range(0, len(lst[0]), 2):
output.append([lst[j][i], lst[j][i+1], lst[j+1][i], lst[j+1][i+1]])
output : [[1, 6, 2, 5], [5, 6, 6, 8], [7, 2, 4, 4], [8, 1, 7, 3]]
Try using:
print([x for i in list(zip(*[[i[:2], i[2:]] for i in lst])) for x in [i[0] + i[1], i[2] + i[3]]])

reverse ascending sequences in a list

Trying to figure out how to reverse multiple ascending sequences in a list.
For instance: input = [1,2,2,3] to output = [2,1,3,2].
I have used mylist.reverse() but of course it reverses to [3,2,2,1]. Not sure which approach to take?
Example in detail:
So lets say [5, 7, 10, 2, 7, 8, 1, 3] is the input - the output should be [10,7,5,8,7,2,3,1]. In this example the first 3 elements 5,7,10 are in ascending order, 2,7,8 is likewise in ascending order and 1,3 also in ascending order. The function should be able to recognize this pattern and reverse each sequence and return a new list.
All you need is to find all non-descreasing subsequences and reverse them:
In [47]: l = [5, 7, 10, 2, 7, 8, 1, 3]
In [48]: res = []
In [49]: start_idx = 0
In [50]: for idx in range(max(len(l) - 1, 0)):
...: if l[idx] >= l[idx - 1]:
...: continue
...: step = l[start_idx:idx]
...: step.reverse()
...: res.extend(step)
...: start_idx = idx
...:
In [51]: step = l[start_idx:]
In [52]: step.reverse()
In [53]: res.extend(step)
In [54]: print(res)
[10, 7, 5, 8, 7, 2, 3, 1]
For increasing subsequences you need to change if l[idx] >= l[idx - 1] to if l[idx] > l[idx - 1]
Walk the list making a bigger and bigger window from x to y positions. When you find a place where the next number is not ascending, or reach the end, reverse-slice the window you just covered and add it to the end of an output list:
data = [5, 7, 10, 2, 7, 8, 1, 3]
output = []
x = None
for y in range(len(data)):
if y == len(data) - 1 or data[y] >= data[y+1]:
output.extend(data[y:x:-1])
x = y
print(output)
There is probably a more elegant way to do this, but one approach would be to use itertools.zip_longest along with enumerate to iterate over sequential element pairs in your list and keep track of each index where the sequence is no longer ascending or the list is exhausted in order to slice, reverse, and extend your output list with the sliced items.
from itertools import zip_longest
d = [5, 7, 10, 2, 7, 8, 1, 3]
results = []
stop = None
for i, (a, b) in enumerate(zip_longest(d, d[1:])):
if not b or b <= a:
results.extend(d[i:stop:-1])
stop = i
print(results)
# [10, 7, 5, 8, 7, 2, 3, 1]
data = [5, 7, 10, 2, 7, 8, 1, 3,2]
def func(data):
result =[]
temp =[]
data.append(data[-1])
for i in range(1,len(data)):
if data[i]>=data[i-1]:
temp.append(data[i-1])
else:
temp.append(data[i-1])
temp.reverse()
result.extend(temp)
temp=[]
if len(temp)!=0:
temp.reverse()
result.extend(temp)
temp.clear()
return result
print(func(data))
# output [10, 7, 5, 8, 7, 2, 3, 1, 2]
You could define a general handy method which returns slices of an array based on condition (predicate).
def slice_when(predicate, iterable):
i, x, size = 0, 0, len(iterable)
while i < size-1:
if predicate(iterable[i], iterable[i+1]):
yield iterable[x:i+1]
x = i + 1
i += 1
yield iterable[x:size]
Now, the slice has to be made when the next element is smaller then the previous, for example:
array = [5, 7, 10, 2, 7, 8, 1, 3]
slices = slice_when(lambda x,y: x > y, array)
print(list(slices))
#=> [[5, 7, 10], [2, 7, 8], [1, 3]]
So you can use it as simple as:
res = []
for e in slice_when(lambda x,y: x > y, array):
res.extend(e[::-1] )
res #=> [10, 7, 5, 8, 7, 2, 3, 1]

trouble appending lists to another list

I have this code which takes a list of numbers and groups together all those that add up to 21. My problem is that in the end I want the numbers to all be lists in a list, but I am having trouble achieving that. Any advise would be appreciated
def twentyone(seq, groups = []):
goal = 21
s = sum(groups)
final = []
if s == goal:
final.append(groups)
print (final)
if s >= goal:
return
for i in range(len(seq)):
n = seq[i]
remaining = seq[i+1:]
twentyone(remaining, groups + [n])
#
seq = [1, 5, 6, 7, 10, 2, 11]
(twentyone(seq))
current output is:
[[1, 5, 6, 7, 2]]
[[1, 7, 2, 11]]
[[5, 6, 10]]
[[10, 11]]
I want the output to be:
[[1, 5, 6, 7, 2], [1, 7, 2, 11], [5, 6, 10], [10, 11]]
You are creating new final list each time when it recursively calls itself. You just have to pass it as a default argument.
def twentyone(seq, groups = [], final = []): #default final list
goal = 21
s = sum(groups)
if s == goal:
final.append(groups)
if s >= goal:
return
for i in range(len(seq)):
n = seq[i]
remaining = seq[i+1:]
twentyone(remaining, groups + [n])
return final
seq = [1, 5, 6, 7, 10, 2, 11]
print twentyone(seq)
Results:-
[[1, 5, 6, 7, 2], [1, 7, 2, 11], [5, 6, 10], [10, 11]]
But the above solution will cause the final list grow each time twentyone function will be called. So we can create a new final list only for the first time it is called using first_call flag as follows:
def twentyone(seq, groups = None, final = None, first_call=True):
if not groups:
groups = []
if first_call:
final = []
goal = 21
s = sum(groups)
if s == goal:
final.append(groups)
if s >= goal:
return
for i in range(len(seq)):
n = seq[i]
remaining = seq[i+1:]
twentyone(remaining, groups + [n], final, False)
return final
seq = [1, 5, 6, 7, 10, 2, 11]
print twentyone(seq)
print twentyone(seq)
Yields:
[[1, 5, 6, 7, 2], [1, 7, 2, 11], [5, 6, 10], [10, 11]]
[[1, 5, 6, 7, 2], [1, 7, 2, 11], [5, 6, 10], [10, 11]]
extending on Tanveers answer (which is the best approach in my opinion), you could also move the final variable outside or even use a static variable. The main problem in your code is that you are creating new final variable in each recursive call. These code below fixes that.
Local variable approach:
final = []
def twentyone(seq, groups = []):
goal = 21
s = sum(groups)
if s == goal:
final.append(groups)
if s >= goal:
return
for i in range(len(seq)):
n = seq[i]
remaining = seq[i+1:]
twentyone(remaining, groups + [n])
seq = [1, 5, 6, 7, 10, 2, 11]
twentyone(seq)
print (final)
Static variable approach:
class myfinal:
final=[]
def twentyone(seq, groups = []):
goal = 21
s = sum(groups)
if s == goal:
myfinal.final.append(groups)
if s >= goal:
return
for i in range(len(seq)):
n = seq[i]
remaining = seq[i+1:]
twentyone(remaining, groups + [n])
seq = [1, 5, 6, 7, 10, 2, 11]
twentyone(seq)
print (myfinal.final)

Categories