Manipulating two lists - python

I am trying to write the code such that, if n[i+1] is not equal to n[i], then the xmove would be m[i+1] - m[i] else, if n[i+1] is equal to n[i], then the xmove at that index is 0, while this continues till n[i+1] is not equal to n[i], then the xmove at that point is the difference between the first and the last m index while the equality condition exists. Same goes for the ymove. The output would be this
xmove = [1, 1, 0, 0, 2, 1]
ymove = [1, 1, 0, 0, 5, 1]
Thank you
m = [1, 2, 3, 4, 5, 6, 7]
n = [1, 2, 3, 3, 3, 8, 9]
xmove = []
ymove = []
first = []
Sum = []
for i in range(len(n)-1):
if n[i+1] == n[1]:
messi = 0
xmove.append(messi)
first.append(n[i])
Sum.append(1)
liit = sum(Sum)
u = first[0] - liit
xmove.append(u)
else:
u = n[i+1] - n[i]
xmove.append(u)

Thanks for the clarification in comments -- what about something like:
m = [1, 2, 3, 4, 5, 6, 7]
n = [1, 2, 3, 3, 3, 8, 9]
ind = range(len(n))
xeq = set()
yeq = set()
xmove = []
ymove = []
for (i,j) in zip(ind[:-1], ind[1:]):
# Handle xmove (based on n) ------------------------------------------------
if n[i] != n[j]:
if not xeq:
xe = m[j] - m[i]
else:
xe = m[max(xeq)] - m[min(xeq)]
xeq.clear()
else:
xe = 0
xeq.update([i,j])
xmove.append(xe)
# Handle ymove (based on m) ------------------------------------------------
if m[i] != m[j]:
if not yeq:
ye = n[j] - n[i]
else:
ye = n[max(yeq)] - n[min(yeq)]
yeq.clear()
else:
ye = 0
yeq.update([i,j])
ymove.append(ye)
print xmove, xmove == [1, 1, 0, 0, 2, 1]
print ymove, ymove == [1, 1, 0, 0, 5, 1]
Output:
[1, 1, 0, 0, 2, 1] True
[1, 1, 0, 0, 5, 1] True
Or using a function:
def get_moves(a, b):
ind = range(len(a))
eq = set()
moves = []
for (i,j) in zip(ind[:-1], ind[1:]):
if b[i] != b[j]:
e = a[j] - a[i] if not eq else a[max(eq)] - a[min(eq)]
eq.clear()
else:
e = 0
eq.update([i,j])
moves.append(e)
return moves
m = [1, 2, 3, 4, 5, 6, 7]
n = [1, 2, 3, 3, 3, 8, 9]
xmove = get_moves(m,n)
ymove = get_moves(n,m)
print xmove, xmove == [1, 1, 0, 0, 2, 1]
print ymove, ymove == [1, 1, 0, 0, 5, 1]
Output:
[1, 1, 0, 0, 2, 1] True
[1, 1, 0, 0, 5, 1] True

Related

Find longest subsequence in a list

I want to write a function that finds the longest ascending sequence in a list in linear time. This seems like a really easy task but without nested for-loops I am stuck somehow. My idea was the following:
if len(L) == 0 or len(L) == 1:
return len(L)
if all(L[i] == L[0] for i in range(len(L)-1)):
return len(L)
left = [1] * len(L)
right = [1] * len(L)
count = 1
for i in range(len(L)-1):
if L[i] <= L[i+1]:
count += 1
left[i+1] = count
else:
count = 1
left[i+1] = count
count = 1
for i in range(len(L)-1, -1, -1):
if L[i] <= L[i-1]:
count += 1
right[i-1] = count
else:
count = 1
right[i-1] = count
idx_left = left.index(max(left))
idx_right = right.index(max(right))
if max(max(left), max(right)) == max(left) and idx_left == len(left) - 1:
return max(left)
You can try this:
mylist=[10,9,8,10,6,5,4,3,2,3]
previous = mylist[0]
max_sublist = [previous]
current_sublist = [previous]
increasing = True
for x in mylist[1:]:
if increasing and previous <= x:
current_sublist.append(x)
elif previous >= x:
increasing = False
current_sublist.append(x)
else:
if len(current_sublist) > len(max_sublist):
max_sublist = current_sublist[:]
current_sublist = [previous, x]
increasing = True
previous = x
if len(current_sublist) > len(max_sublist):
max_sublist = current_sublist[:]
print(f"{max_sublist=}\n{len(max_sublist)=}")
It gives:
max_sublist=[8, 10, 6, 5, 4, 3, 2]
len(max_sublist)=7
try working on the diffrences between 2 values,
I'm not sure it works for every case but it's a start in o(n),
added 1 to the resault in the end cause it's counting comparisons so the last value will not be counted
def sequance(seq):
max_len = 0
current_len = 0
going_down = False
for i in range(len(seq)-1):
if seq[i] == seq[i+1]:
current_len += 1
if max_len < current_len:
max_len = current_len
continue
if seq[i] < seq[i+1]:
if going_down:
current_len = 1
going_down = False
continue
else:
current_len +=1
if max_len < current_len:
max_len = current_len
continue
if seq[i] > seq[i+1]:
if going_down:
current_len += 1
if max_len < current_len:
max_len = current_len
continue
else:
going_down = True
current_len += 1
if max_len < current_len:
max_len = current_len
return max_len + 1
[10, 9, 8, 10, 6, 5, 4, 3, 2, 3] # 7
[4, 5, 3, 2, 1, 3, 6, 4, 7] # 5
[10, 9, 8, 7, 6, 5, 4, 3, 2, 3] # 9
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1] # 10
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 10
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] # 19
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0] # 10
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1] # 10
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1] # 9
[1, 1, 0, 0, 0, 0, 0, 0, 0, 1] # 9
[1, 1, 1, 0, 0, 0, 0, 0, 0, 2] # 9
You can consider the increasing/decreasing state of grouped identical values, and keep track of the previous length. The complexity is O(n) with a single pass on the input:
from itertools import groupby
def sequence(lst):
max_len = 0
prev = float('nan')
prev_len = 0
running_len = 0
increasing = False
for k, g in groupby(lst):
L = len(list(g))
if k < prev:
running_len += L
increasing = False
else:
if increasing:
running_len += L
else:
max_len = max(max_len, running_len)
running_len = L + prev_len
increasing = True
prev = k
prev_len = L
return max(max_len, running_len)
sequence([10,9,8,10,6,5,4,3,2,3])
Output: 7
NB. itertools.groupby is just a convenience to avoid having to handle the successive identical values. But you don't have to use it and can track those yourself.
Other examples:
sequence([10, 9, 8, 10, 6, 5, 4, 3, 2, 3])
#7 * * * * * * *
sequence([4, 5, 3, 2, 1, 3, 6, 4, 7])
#5 * * * * *
sequence([10, 9, 8, 7, 6, 5, 4, 3, 2, 3])
#9 * * * * * * * * *
sequence([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])
#10 * * * * * * * * * *
sequence([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
#10 * * * * * * * * * *
sequence([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1])
#19 * * * * * * * * * * * * * * * * * * *
sequence([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
#10 * * * * * * * * * *
sequence([0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
#10 * * * * * * * * * *
sequence([1, 0, 0, 0, 0, 0, 0, 0, 0, 1])
#9 * * * * * * * * *
sequence([1, 1, 0, 0, 0, 0, 0, 0, 0, 1])
#9 * * * * * * * * *
sequence([1, 1, 1, 0, 0, 0, 0, 0, 0, 2])
#9 * * * * * * * * *
refactoring the code
This is the exact same logic as above but tests have been combined, intermediate variables removed, etc.
from itertools import groupby
def sequence(lst):
max_len = prev_len = running_len = 0
prev = float('nan')
decreasing = False
for k, g in groupby(lst):
if k < prev:
decreasing = True
elif decreasing:
max_len = max(max_len, running_len)
running_len = prev_len
decreasing = False
prev = k
prev_len = len(list(g))
running_len += prev_len
return max(max_len, running_len)

Python list appending in a loop not working as intended

A have a case where i receive a integer value(cents) and need to find all the change possibilities with quarters, dimes, nickels and pennies, and return a set of all the ways.
I've made some code that works partially.
QUARTER = 25
DIME = 10
NICKEL = 5
PENNIE = 1
def makeChange(value):
way_list = []
way = [0, 0, 0, 0]
for q_q in range((value // QUARTER) + 1):
way[0] = q_q
value_after_Q = value - (q_q * QUARTER)
for d_q in range((value_after_Q // DIME) + 1):
way[1] = d_q
value_after_D = value_after_Q - (d_q * DIME)
for n_q in range((value_after_D // NICKEL) + 1):
way[2] = n_q
value_after_N = value_after_D - (n_q * NICKEL)
p_q = value_after_N // PENNIE
way[3] = p_q
print(way) # this print shows my results one by one
way_list.append(way) # but this append only appends the last possible result, multiple times
# makes a set:
way_list = [
_way
for ind, _way in enumerate(way_list)
if _way not in way_list[:ind]
]
return way_list
print(makeChange(25))
The print on the last loop prints me:
[0, 0, 0, 25]
[0, 0, 1, 20]
[0, 0, 2, 15]
[0, 0, 3, 10]
[0, 0, 4, 5]
[0, 0, 5, 0]
[0, 1, 0, 15]
[0, 1, 1, 10]
[0, 1, 2, 5]
[0, 1, 3, 0]
[0, 2, 0, 5]
[0, 2, 1, 0]
[1, 0, 0, 0]
Which is not wrong, but i need it inside a set.
When i try to append the "way" list to the propper "way_list", it only appends the [1, 0, 0, 0], multiple times.

Use clipping or zero padding

Write a function that accept an array of N elements, and converts it into a 9-element array. Use clipping or zero padding to obtain the desired output. Care should be taken to place the middle element of the input array as the middle element of output array.
Examples
A = [ 2, 5, 1 ] # N == 3, so zero padding to make the output size 9
output = [0, 0, 0, 2, 5, 1, 0, 0, 0]
A = [ 2, 3, 7, 4 ]
output = [0, 0, 2, 3, 7, 4, 0, 0, 0] or [0, 0, 0, 2, 3, 7, 4, 0, 0] # Because there are two middle elements if N is even
A = [ 1, 3, 3, 4, 7, 6, 4, 3, 3, 2, 2, 2, 1 ] # N == 13, so remove 4 elements (2 at the right, 2 at the left) to make the output size 9
output = [3, 4, 7, 6, 4, 3, 3, 2, 2]
A = [ 1, 2, 3, 3, 4, 7, 6, 4, 3, 3, 2, 2, 2, 1 ]
output = [3, 3, 4, 7, 6, 4, 3, 3, 2] or [3, 4, 7, 6, 4, 3, 3, 2, 2]
Imagine you want an output list of n=9 with zeros padding and an input list A.
Then treat the thing as separate problems:
If len(A) == n return A
If len(A) > n then return the middle n elements of A.
Else return a list that starts with (n - len(A)) // 2 zeros, then A, then ends with n - (n - len(A)) // 2 - len(A) zeros (however much is left over from n elements).
E.g.
def fulllist(A, n):
if len(A) == n:
return A
if len(A) > n:
start = (len(A) - n) // 2
return A[start:start+n]
if len(A) < n:
leftpad = [0] * ((n - len(A)) // 2)
rightpad = [0] * (n - len(leftpad) - len(A))
return leftpad + A + rightpad
This gives the following as output:
>>> fulllist([2, 5, 1], 9)
[0, 0, 0, 2, 5, 1, 0, 0, 0]
>>> fulllist([2, 3, 7, 4], 9)
[0, 0, 2, 3, 7, 4, 0, 0, 0]
>>> fulllist([1, 3, 3, 4, 7, 6, 4, 3, 3, 2, 2, 2, 1], 9)
[3, 4, 7, 6, 4, 3, 3, 2, 2]
>>> fulllist([1, 2, 3, 3, 4, 7, 6, 4, 3, 3, 2, 2, 2, 1], 9)
[3, 3, 4, 7, 6, 4, 3, 3, 2]
The above function was written to match the pseudocode, but it would be better to alter it slightly, eliminating case 1. by treating it as a special case of 2. or 3.. That way the code is shorter, and more important, the function always returns a brand new list in every case instead of sometimes returning a reference to the input list, which could get confused in subsequent code and lead to some bugs. I chose to merge 1. with 2.
def fulllist(A, n):
if len(A) >= n:
start = (len(A) - n) // 2
return A[start:start+n]
else:
leftpad = [0] * ((n - len(A)) // 2)
rightpad = [0] * (n - len(leftpad) - len(A))
return leftpad + A + rightpad
Or you can shorten the code further by abusing the fact that [0] * -1 == [].
def fulllist(A, n):
leftpad = [0] * ((n - len(A)) // 2)
rightpad = [0] * (n - len(leftpad) - len(A))
start = (len(A) - n) // 2 if len(A) > n else 0
contents = A[start:start+n]
return leftpad + contents + rightpad
Although that may be going too far for some and it might make the code harder to understand. I like it though.
you can try something like this:
def padding(arr,n):
diff = abs(n - len(arr))
start, end = int(diff / 2), diff - int(diff / 2)
if len(arr) < n:
for i in range(start):
arr.insert(0,0)
for i in range(end):
arr.append(0)
else:
for i in range(start):
arr.pop(0)
for i in range(end):
arr.pop(-1)
return arr
A = [ 1, 3, 3, 4, 7, 6, 4, 3, 3, 2, 2, 2, 1 ]
print(padding(A,9))
Try -
def padding(l1):
flag = 0
while len(l1)>=9:
if len(l1) == 9:
return l1
if flag %2== 0:
l1.pop()
else:
l1.pop(0)
flag+=1
if len(l1)<9:
iterations = (9- len(l1))//2
for _ in range(iterations):
l1.insert(0,0)
l1.append(0)
if iterations % 2 == 0:
l1.append(0)
return l1
padding(A)

Generate a list based on the index of another list

I have a list:
hash_table = [1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1]
I want to change this to:
result = [[0, 0], [1, 2], [4, 5]]
How to generate:
array: [1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1]
map: 0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0
# start to end, generate the result like `[int(start), int(end)]`
combine them:[[0, 0], [1, 2], [4, 5]]
0 and 1 wouldn't appear in pairs. So the numbers in result must be an integer.
What I have tried:
hash_table = [1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1]
output = [[]]
for pre, next_ in zip(hash_table, hash_table[1:]):
output[-1].append(pre)
if {next_, pre} == {0, 1}:
output.append([])
output[-1].append(hash_table[-1])
# the output is [[1], [0], [1, 1, 1], [0, 0, 0], [1, 1, 1]]
start = index = 0
result = []
while index < len(output):
# output[index]
if output[0] != 0:
res.append([start, math.ceil(len(output[index]))])
# I don't know how to handle the list "output".
# I couldn't know it. My mind has gone blank
start += len(output[index])/2
Any good ideas? I thought I made it too complicated.
You can use itertools.groupby to group the 0s and 1s:
import itertools
hash_table = [1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1]
result = []
cur_ind = 0
for (val, vals) in itertools.groupby(hash_table):
vals = list(vals) # itertools doesn't make it a list by default
old_ind = cur_ind
cur_ind += len(vals)
if val == 0:
continue
result.append([old_ind // 2, (cur_ind - 1) // 2])
print(result)
Essentially, itertools.groupby will give an iterator of [(1, [1]), (0, [0]), (1, [1, 1, 1]), (0, [0, 0, 0]), (1, [1, 1, 1])] (more or less). We can iterate through this iterator and keep track if the index we're on by adding the length of the sublist to the current index. If the value is 1, then we have a run of ones so we append it to the results. The old_ind // 2 is integer division and is equivalent to int(old_ind / 2).
You could use groupby from itertools library:
import itertools
hash_table = [1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1]
s = "".join(map(str, hash_table)) # s = "10111000111"
gs = [(i, list(g)) for i, g in itertools.groupby(s)]
idx, result = 0, []
for i, g in gs: # i can be '1' or '0' (i.e, if the group consist in 1's or 0's)
if i == '1':
result.append([idx/2, (idx + len(g) - 1)/2])
idx += len(g)
return result

How to add a sublist to a sublist?

I want to append a sublist to the previous sublist under certain circumstances, i.e. if its length is less than 2. So, the length of [5] less than 2 and now the previous list is to be extended with the 5 (a+b).
a = [1,1,1,1]
b = [5]
c = [1,1,1]
d = [1,1,1,1,1]
e = [1,2]
f = [1,1,1,1,1,1]
L = [a,b,c,d,e,f]
print 'List:', L
def short(lists):
result = []
for value in lists:
if len(value) <= 2 and result:
result[-1] = result[-1] + value
return result
result = short(L)
print 'Result:', result
The result should be: [[1, 1, 1, 1, 5], [1, 1, 1], [1, 1, 1, 1, 1, 2], [1, 1, 1, 1, 1, 1]]
But from my code, I get: []
This might help
Ex:
a = [1,1,1,1]
b = [5]
c = [1,1,1]
d = [1,1,1,1,1]
e = [1,2]
f = [1,1,1,1,1,1]
L = [a,b,c,d,e,f]
print( 'List:', L)
def short(lists):
result = []
for value in lists:
if len(value) <= 2: #check len
result[-1].extend(value) #extend to previous list
else:
result.append(value) #append list.
return result
result = short(L)
print( 'Result:', result)
Output:
List: [[1, 1, 1, 1], [5], [1, 1, 1], [1, 1, 1, 1, 1], [1, 2], [1, 1, 1, 1, 1, 1]]
Result: [[1, 1, 1, 1, 5], [1, 1, 1], [1, 1, 1, 1, 1, 1, 2], [1, 1, 1, 1, 1, 1]]
Change your function to:
def short(lists):
result = []
for value in lists:
if len(value) < 2 and result:
result[-1].extend(value)
else:
result.append(value)
return result

Categories