Deciding if two lists are cyclic permutations of eachother - python

I was assigned to write a function that accept two lists and returns True if the other list is a cyclic permutation of the other.
I wrote a function that accepts two lists and changes between the first and the last place. After that i wrote a function that calls the first function using a for loop and returns True at the end of the loop if it was true for each i.
I tries running the code and ive encountered several error messages:
File "C:/WinPython-64bit-3.5.2.2Qt5/settings/.spyder-py3/temp.py", line 13, in cyclic
if change_position(lst1, lst2):
File "C:/WinPython-64bit-3.5.2.2Qt5/settings/.spyder-py3/temp.py", line 5, in change_position
lst3[0] = lst4[len(lst4)]
Here is my code:
def change_position(lst3, lst4):
if len(lst3) != len(lst4):
print(False)
else:
lst3[0] = lst4[len(lst4)]
def cyclic(lst1, lst2):
if len(lst1) != len(lst2):
print(False)
else:
for i in range(len(lst1)):
if change_position(lst1, lst2):
print(True)
else:
print(False)
cyclic([1, 2, 3, 4], [4, 1, 2, 3])
Does anyone know how i can fix this so the function will work?
Thanks in advance for all of your help.

No need to reorder your list, only index computations will do
def is_cyc_perm (list1, list2):
if len (list1) == len (list2):
for shift in range (len (list1)):
for i in range (len (list1)):
if list1 [i] != list2 [(i + shift) % len (list1)]:
break
else:
return True
else:
return False
else:
return False
print (is_cyc_perm ([8, 2, 5, 7], [8, 2, 5, 7]))
print (is_cyc_perm ([7, 8, 2, 5], [8, 2, 5, 7]))
print (is_cyc_perm ([2, 5, 7, 8], [8, 2, 5, 7]))
print (is_cyc_perm ([8, 5, 2, 7], [8, 2, 5, 7]))
print (is_cyc_perm ([7, 2, 5, 8], [8, 2, 5, 7]))
print (is_cyc_perm ([8, 2, 5, 3], [8, 2, 5, 7]))

The list index starts with 0, you should use range(0, len(list)-1).
def change_position(lst3, lst4):
if len(lst3) != len(lst4):
print(False)
else:
lst3[0] = lst4[len(lst4)-1]
def cyclic(lst1, lst2):
if len(lst1) != len(lst2):
print(False)
else:
for i in range(len(lst1)-1):
if change_position(lst1, lst2):
print(True)
else:
print(False)

Rotating a double linked list is a quick operation with pointers. You can simply try all rotations if there is a match.
The collections module also provides Counter which can be used for a quick test if both lists have the same count of the same elements. It is just a stronger version of the obvious same length check.
import collections
def is_cyc_perm(seq1, seq2):
mset1 = collections.Counter(seq1)
mset2 = collections.Counter(seq2)
if mset1 != mset2:
return False
size = len(seq1)
deq1 = collections.deque(seq1)
deq2 = collections.deque(seq2)
for _ in range(size):
deq2.rotate()
if deq1 == deq2:
return True
return False

Related

list comprehension Error " IndexError: list index out of range "

I am trying to make list comprehension for the below code, the code works fine if comprehension not used.
This code is used to return the missing number in a sequence of numbers that have a constant difference between the consecutive terms of a given series of numbers.
def find_missing(sequence):
difference = min(sequence[1] - sequence[0], sequence[-1] - sequence[-2])
# for index in range(len(sequence)):
# if sequence[index] + difference != sequence[index+1]:
# return sequence[index] + difference
# return [index for index in range(len(sequence))]
return [sequence[index]+difference for index in range(len(sequence)) if sequence[index]+difference != sequence[index+1]]
print(find_missing([1, 2, 3, 4, 6, 7, 8, 9])) # ==5
print(find_missing([1, 3, 5, 9, 11])) # == 7
print(find_missing([1, 3, 4])) # == 2
I have an error message when using comprehension.
Error:
IndexError: list index out of range
You are getting an error because index+1 in sequence[index+1] is one bigger than the array on the last iteration. Python generally discourages using indexes for loops — partially because it's so easy to create these kind of bugs.
If you want to compare adjacent elements, you can instead loop over zip(sequence, sequence[1:]). This will give you pairs that you can then compare — it's easier to read and you don't need to worry about index errors:
def find_missing(sequence):
difference = min(sequence[1] - sequence[0], sequence[-1] - sequence[-2])
return [ f + difference
for f, n in zip(sequence, sequence[1:])
if f + difference != n ]
print(find_missing([1, 2, 3, 4, 6, 7, 8, 9])) # == [5]
print(find_missing([1, 3, 5, 9, 11])) # == [7]
print(find_missing([1, 3, 4])) # == [2]

How to I write a recursive function for split even and odd indices of array?

This is question for my interview.
Write a recursive function that does the following:
Input: An array A of length N. N is an even number and N >= 2.
Output: A reordered array B. The first half of B contains A’s elements with even indices. The second half of B contains A’s elements with odd indices. Convention: the first index of an array is 0 (and thus it is an even number).
Input 1: [4, 8, 12, 16]
For this array, the indices and the values are as follows:
Index: 0, 1, 2, 3
Value: 4, 8, 12, 16
Thus, the output is as follows:
Expected output 1: [4, 12, 8, 16]
ADDITIONAL TEST CASE
Input 2: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Expected output 2: [1, 3, 5, 7, 9, 2, 4, 6, 8, 10]
TASK
Write a recursive function in a programming language of your choice (as if you are writing real code to be used on a production server) for the above problem
In addition to the main function, you are free to write helper functions (if needed)
The code should have as few lines as possible (but it should still be clear and readable)
Note: Your recursive function must show the 'spirit' of a recursive function (not just the recursive form of a for loop)
Here is my code:
def slove(array, deep=0):
'''para:
array: list input.
return: list.
!!!Do not set value for deep!!!'''
if len(array) > 2:
if deep > 0:
for i in xrange(0, len(array), 2):
array[i], array[i + 1] = array[i + 1], array[i]
left = array[0]
right = array[-1]
array = array[1:-1]
array = slove(array, deep + 1)
array.insert(0, left)
array.append(right)
return array
else:
array[0], array[-1] = array[-1], array[0]
return array
if __name__ == '__main__':
array = map(int, raw_input('Enter array with sep is space key: ').split(' '))
# array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print slove(array)
He said that it is wrong because I use loop in program. He is correct? So how to solve it?
Why not just use slicing?
lst = [11,12,13,14,15,16]
lst[0::2] + lst[1::2]
Returns:
[11, 13, 15, 12, 14, 16]
This pseudocode function might help:
Let A[n] and B[n] be the 2 arrays where n is the size.
Then we will call the following method rearrange(0,0):
rearrange(int i, int j) {
b[j] = a[i];
b[j+n/2] = a[i+1];
if (j < n/2-1)
rearrange(i+2,j+1);
}
In this method, i jumps 2 times each therefore the odd items get stored in the first half of the output array. For the second half, j+n/2 saves the even items.
This is one (awkward) way to do it:
def even_odd_split(seq):
"""
>>> even_odd_split([4, 8, 12, 16])
[4, 12, 8, 16]
>>> even_odd_split([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
[1, 3, 5, 7, 9, 2, 4, 6, 8, 10]
"""
assert(len(seq) % 2 == 0)
assert(len(seq) > 1)
def _split(seq):
if len(seq) == 0: return [], []
a, b = _split(seq[2:])
return [seq[0]] + a, [seq[1]] + b
a, b = _split(seq)
return a + b
if __name__ == '__main__':
import doctest
doctest.testmod()
I would solve it like this:
def f(l):
if len(l) == 1:
# only one element left
return l
if len(l) % 2 == 0:
# length is even
return l[:1] + f(l[1:])
else:
# length is odd
return f(l[1:]) + l[:1]
Every invocation of the function removes one element from the list and either puts it at the beginning or at the end of the resulting list.
It does not produce the given “expected” outputs, because the elements of the list appear in another order than they appear in the input list, but it matches the specification… and also, I think it’s pretty simple.

built-in max heap API in Python

Default heapq is min queue implementation and wondering if there is an option for max queue? Thanks.
I tried the solution using _heapify_max for max heap, but how to handle dynamically push/pop element? It seems _heapify_max could only be used during initialization time.
import heapq
def heapsort(iterable):
h = []
for value in iterable:
heapq.heappush(h, value)
return [heapq.heappop(h) for i in range(len(h))]
if __name__ == "__main__":
print heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8, 0])
Edit, tried _heapify_max seems not working for dynamically push/pop elements. I tried both methods output the same, both output is, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].
def heapsort(iterable):
h = []
for value in iterable:
heapq.heappush(h, value)
return [heapq.heappop(h) for i in range(len(h))]
def heapsort2(iterable):
h = []
heapq._heapify_max(h)
for value in iterable:
heapq.heappush(h, value)
return [heapq.heappop(h) for i in range(len(h))]
if __name__ == "__main__":
print heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8, 0])
print heapsort2([1, 3, 5, 7, 9, 2, 4, 6, 8, 0])
Thanks in advance,
Lin
In the past I have simply used sortedcontainers's SortedList for this, as:
> a = SortedList()
> a.add(3)
> a.add(2)
> a.add(1)
> a.pop()
3
It's not a heap, but it's fast and works directly as required.
If you absolutely need it to be a heap, you could make a general negation class to hold your items.
class Neg():
def __init__(self, x):
self.x = x
def __cmp__(self, other):
return -cmp(self.x, other.x)
def maxheappush(heap, item):
heapq.heappush(heap, Neg(item))
def maxheappop(heap):
return heapq.heappop(heap).x
But that will be using a little more memory.
There is a _heappop_max function in the latest cpython source that you may find useful:
def _heappop_max(heap):
"""Maxheap version of a heappop."""
lastelt = heap.pop() # raises appropriate IndexError if heap is empty
if heap:
returnitem = heap[0]
heap[0] = lastelt
heapq._siftup_max(heap, 0)
return returnitem
return lastelt
If you change the heappush logic using heapq._siftdown_max you should get the desired output:
def _heappush_max(heap, item):
heap.append(item)
heapq._siftdown_max(heap, 0, len(heap)-1)
def _heappop_max(heap):
"""Maxheap version of a heappop."""
lastelt = heap.pop() # raises appropriate IndexError if heap is empty
if heap:
returnitem = heap[0]
heap[0] = lastelt
heapq._siftup_max(heap, 0)
return returnitem
return lastelt
def heapsort2(iterable):
h = []
heapq._heapify_max(h)
for value in iterable:
_heappush_max(h, value)
return [_heappop_max(h) for i in range(len(h))]
Output:
In [14]: heapsort2([1,3,6,2,7,9,0,4,5,8])
Out[14]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
In [15]: heapsort2([7, 8, 9, 6, 4, 2, 3, 5, 1, 0])
Out[15]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
In [16]: heapsort2([19,13,15,17,11,10,14,20,18])
Out[16]: [20, 19, 18, 17, 15, 14, 13, 11, 10]
In [17]: heapsort2(["foo","bar","foobar","baz"])
Out[17]: ['foobar', 'foo', 'baz', 'bar']

Python - iterating beginning with the middle of the list and then checking either side

Really not sure where this fits. Say, I have a list:
>>>a = [1, 2, 3, 4, 5, 6, 7]
How can I iterate it in such a way, that it will check 4 first, then 5, then 3, then 6, and then 2(and so on for bigger lists)? I have only been able to work out the middle which is
>>>middle = [len(a)/2 if len(a) % 2 = 0 else ((len(a)+1)/2)]
I'm really not sure how to apply this, nor am I sure that my way of working out the middle is the best way. I've thought of grabbing two indexes and after each iteration, adding 1 and subtracting 1 from each respective index but have no idea how to make a for loop abide by these rules.
With regards as to why I need this; it's for analysing a valid play in a card game and will check from the middle card of a given hand up to each end until a valid card can be played.
You can just keep removing from the middle of list:
lst = range(1, 8)
while lst:
print lst.pop(len(lst)/2)
This is not the best solution performance-wise (removing item from list is expensive), but it is simple - good enough for a simple game.
EDIT:
More performance stable solution would be a generator, that calculates element position:
def iter_from_middle(lst):
try:
middle = len(lst)/2
yield lst[middle]
for shift in range(1, middle+1):
# order is important!
yield lst[middle - shift]
yield lst[middle + shift]
except IndexError: # occures on lst[len(lst)] or for empty list
raise StopIteration
To begin with, here is a very useful general purpose utility to interleave two sequences:
def imerge(a, b):
for i, j in itertools.izip_longest(a,b):
yield i
if j is not None:
yield j
with that, you just need to imerge
a[len(a) / 2: ]
with
reversed(a[: len(a) / 2])
You could also play index games, for example:
>>> a = [1, 2, 3, 4, 5, 6, 7]
>>> [a[(len(a) + (~i, i)[i%2]) // 2] for i in range(len(a))]
[4, 5, 3, 6, 2, 7, 1]
>>> a = [1, 2, 3, 4, 5, 6, 7, 8]
>>> [a[(len(a) + (~i, i)[i%2]) // 2] for i in range(len(a))]
[4, 5, 3, 6, 2, 7, 1, 8]
Here's a generator that yields alternating indexes for any given provided length. It could probably be improved/shorter, but it works.
def backNforth(length):
if length == 0:
return
else:
middle = length//2
yield middle
for ind in range(1, middle + 1):
if length > (2 * ind - 1):
yield middle - ind
if length > (2 * ind):
yield middle + ind
# for testing:
if __name__ == '__main__':
r = range(9)
for _ in backNforth(len(r)):
print(r[_])
Using that, you can just do this to produce a list of items in the order you want:
a = [1, 2, 3, 4, 5, 6, 7]
a_prime = [a[_] for _ in backNforth(len(a))]
In addition to the middle elements, I needed their index as well. I found Wasowski's answer very helpful, and modified it:
def iter_from_middle(lst):
index = len(lst)//2
for i in range(len(lst)):
index = index+i*(-1)**i
yield index, lst[index]
>>> my_list = [10, 11, 12, 13, 14, 15]
>>> [(index, item) for index, item in iter_from_middle(my_list)]
[(3, 13), (2, 12), (4, 14), (1, 11), (5, 15), (0, 10)]

quicksort divide-and-conquer returns incorrect partial answer

My program does not return the correct question in the end but it shows correct ones in the intermediate results. I needs help, thanks.
Output sample:
sort begin: A,start,end [3, 5, 2, 1, 7, 6, 8, 4] 0 7
sort begin: A,start,end [2, 1, 3, 5, 7, 6, 8, 4] 0 1
sort begin: A,start,end [1, 2, 3, 5, 7, 6, 8, 4] 3 7
sort begin: A,start,end [1, 2, 3, 4, 5, 6, 8, 7] 3 3
sort begin: A,start,end [1, 2, 3, 4, 5, 6, 8, 7] 5 7
sort begin: A,start,end [1, 2, 3, 4, 5, 6, 8, 7] 5 4
sort begin: A,start,end [1, 2, 3, 4, 5, 6, 8, 7] 6 7
####################################################
final result [1, 2, 3, 5, 4, 6, 8, 7]
My code:
def qSort(A,start,end):
print "sort begin: A,start,end",A,start,end
if start >= end:
return A
elif end == start + 1:
if A[start] > A[end]:
A[start],A[end] = A[end],A[start]
return A
else:
i = start + 1
j = i
p = A[start]
while j < end:
j = j + 1
if p > A[j]:
A[i],A[j] = A[j],A[i]
i = i + 1
A = A[0:start] + A[start+1:i]+ [p] + A[i:end+1]
qSort(A,start,i-2)
qSort(A,i,end)
return A
print "###################"
myarray = [3,5,2,1,7,6,8,4]
result = qSort(myarray,0,7)
print "final result",result
Sorry for my lack luster comments. I reviewed your code and realized it was correct! You have one minor coding mistake which I will point out and then explain. In your else block you currently have:
else:
# Bunch of correct stuff
# ...
# Stuff that is ALMOST correct
qSort(A,start,i-2)
qSort(A,i,end)
return A
you need to change this to:
else:
# Bunch of correct stuff
# ...
# Stuff that is definitely correct
A = qSort(A,start,i-2)
A = qSort(A,i,end)
return A
Without going too deeply into this, your function does not discriminate between list references and newly created lists. If you put print A in you elif block right before return A you will notice that on the final iteration, your sort, as is, does everything correctly, and produces the correct list!
Unfortunately, the call that produced this change was one of the lines I've mentioned above which calls the sort but doesn't store the resulting list returned by the recursive function call!
My simple change just takes the modified list returned from secondary function calls to qSort and reassigns the variable A.
Weirdly, this behavior actually worked ok for you sometimes for reasons I cannot fully explain (like the first time you enter your `elif' block which does the right thing and modifies the list correctly). I am sure someone smarter than I surely can explain the odd behavior.
Alternatively, you could come up with a simple way to count recursion depth (number of times your function calls itself) and print that out while debugging with some breakpoints in your favorite IDE.
Heres how you could do that with global variables:
recursion_depth = -1
def qSort(A,start,end):
global recursion_depth
recursion_depth += 1
print "sort begin: A,start,end,level",A,start,end,recursion_depth
# bunch of code edited out for brevity
# ...
result = qSort(myarray,0,7)
print "final result",result

Categories