Why does my code fail on this SIMPLE exercise? - python

I am doing a coding exercise:
Given a sequence of integers as an array, determine whether it is possible to obtain a strictly increasing sequence by removing no more than one element from the array.
Example
For sequence = [1, 3, 2, 1], the output should be
false;
There is no one element in this array that can be removed in order to get a strictly increasing sequence.
For sequence = [1, 3, 2], the output should be
true;
You can remove 3 from the array to get the strictly increasing sequence [1, 2]. Alternately, you can remove 2 to get the strictly increasing sequence [1, 3].
.
So I wrote this code:
def almostIncreasingSequence(sequence):
first_list, second_list = [x for x in sequence], [x for x in sequence]
for i in range(len(sequence)-1):
if sequence[i] >= sequence[i+1]:
first_list.remove(sequence[i])
second_list.remove(sequence[i+1])
break
if first_list == sorted(set(first_list)) or second_list == sorted(set(second_list)):
return True
else:
return False
The code passes 13/15 tests.
Below are the 2 inputs that my code fails on:
[1, 2, 3, 4, 3, 6]
[3, 5, 67, 98, 3]
Both inputs should return True but my code returns False. Any thoughts?

Read about list.remove:
Remove the first item from the list whose value is x. It is an error if there is no such item.
>>> l = [1, 2, 3, 4, 3, 6]
>>> l.remove(3)
>>> print(l)
[1, 2, 4, 3, 6]
Instead of remove(value), use pop(index):
first_list.pop(i)
second_list.pop(i+1)

Take your first list, [1, 2, 3, 4, 3, 6]. Once you run the for loop over first_list and second_list, the values of those variables are:
In [9]: first_list
Out[9]: [1, 2, 3, 3, 6]
In [10]: second_list
Out[10]: [1, 2, 4, 3, 6]
The first part of the if is False because:
In [12]: sorted(set(first_list))
Out[12]: [1, 2, 3, 6]
By putting the list into a set, you've lost one of the 3's.
The second part of the if is False because second_list is not sorted.
So, both parts of the if statement are False, and your function returns False.

Related

Combine n elements in first half of list with elements in other half of a list, if number of elements in a list is greater than 2

I have a problem with dealing with elements in a list. To be precise in a list of lists. For example, I have list of elements that are read from a file:
list_1 = [['void', None], ['uint8', 'f_MbistTestType_u8'], ['uint8', 'uint32', 'f_MbistTestType_u8', 'f_chip_id_u32'], ['void', None], ['void', None], ['void', None], ['void', None]]
In this case third element has more than two elements. I want to switch element 2 with element 3. So it would look like this:
list_1[2] = ['uint8', 'f_MbistTestType_u8', 'uint32', 'f_chip_id_u32']
If there would be 6 elements i.e.
list_example = ['uint8', 'uint32', 'void', 'f_chip_id_u32', 'f_MbistTestType_u8', None]
After the operation it should look like this:
list_example_sorted = ['uint8', 'f_chip_id_u32', 'uint32', 'f_MbistTestType_u8', 'void', None]
Right now I know how to get those elements in case I have only one occurrence of more than 2 elements, but don't know how to switch their places and also what to do in case I have more than one occurrence:
for elements in list_1:
print(elements)
if len(elements) > 2:
list_el = elements
print(list_el)
I tried to pop them out and append, but it won't scale well with more than 4 elements.
I tried to use swap function, but it seems that it doesn't work or I used it wrong?
Going by an input of [1, 1, 1, 2, 2, 2] with the desired output [1, 2, 1, 2, 1, 2], i.e. you want the first element of the left half followed by the first element of the right half and so forth.
To make it more obvious:
input = [1, 2, 3, 4, 5, 6]
output = [1, 4, 2, 5, 3, 6]
Define a function combine_inplace that combines the ith element of the left half with the ith element of the right half of l:
def combine_inplace(l):
mid = len(l) // 2
ptr = 0
for left, right in zip(l[:mid], l[mid:]):
l[ptr], l[ptr+1] = left, right
# Increment pointer ptr by 2 for the next combination
ptr += 2
combine_inplace mutates the passed list l
left half and right half are created using slice operator
use zip to iterate over both list
increment ptr by 2 to get to the next list indices for l
If you don't want to mutate the list itself you can instead create a new list combined that is returned by the function combine:
def combine(l):
mid = len(l) // 2
combined = []
for left, right in zip(l[:mid], l[mid:]):
combined.extend((left, right))
return combined
Does not mutate the passed list l
Initialise empty list combined to store the combined values
use zip to iterate over both list halves
Returns the list combined
This uses the same logic as combine_inplace but you keep the original list intact.
Both functions combine the elements of the left half with the right half of a given list. The only difference is that with combine you have to store the returned list in a variable to access it.
>> l = [1, 1, 1, 2, 2, 2]
>> combine_inplace(l)
>> print(l)
[1, 2, 1, 2, 1, 2]
>> input_list = [1, 2, 3, 4, 5, 6]
>> output_list = combine(input_list)
>> print(output_list)
[1, 4, 2, 5, 3, 6]
Now using either combine or combine_inplace to combine elements of lists with a length > 2 inside a list:
ll = [[1, 2], [1, 2], [1, 1, 2, 2], [1, 2], [1, 2, 3, 4, 5, 6]]
# Non-destructive way using combine to create a new list comb_ll
comb_ll = []
for el in ll:
if len(el) > 2:
el = combine(el)
comb_ll.append(el)
# Mutates the original list
for i in range(len(ll)):
if len(ll[i]) > 2:
combine_inplace(ll[i])
In both cases you'll get the same result:
>> print(comb_ll)
[[1, 2], [1, 2], [1, 2, 1, 2], [1, 2], [1, 4, 2, 5, 3, 6]]
>> print(ll)
[[1, 2], [1, 2], [1, 2, 1, 2], [1, 2], [1, 4, 2, 5, 3, 6]]

I'm trying to rotate an array about a given index in python

case 1:
a=[1,2,3,4,5]
index k=2
a[:k],a[k:]=a[k:],a[:k]
When I swap array elements like this. I got this output.
**OUTPUT:[3, 4, 1, 2]
case 2:
b=[1,2,3,4,5]
b[k:],b[:k]=b[:k],b[k:]
but when I swap array elements like this i got this.The only difference is the order of swapping.
OUTPUT:[3, 4, 5, 1, 2]
If we swap two variables, the order of swapping doesn't make a difference.
i.e a,b=b,a is same as b,a=a,b.
Why this is not working in the case of lists/array?
The right hand side is evaluated fully before any assignments are done. Subsequently, the assignments are performed in left to right order.
So the first case evaluates to:
a[:2], a[2:] = [3, 4, 5], [1, 2]
The first assignment replaces the first two elements [1, 2] by the three elements [3, 4, 5], so now we have a == [3, 4, 5, 3, 4, 5]. The second assignment then replaces element 2 onwards by [1, 2], so it results in a == [3, 4, 1, 2].
In the second case, we have:
b[2:], b[:2] = [1, 2], [3, 4, 5]
The first assignment replaces from element 2 onwards by [1, 2] resulting in b == [1, 2, 1, 2]. The second assignment replaces the first two elements by [3, 4, 5], giving b == [3, 4, 5, 1, 2].
You may have noticed by now that this is rather tricky to think about and sometimes works mostly by accident, so I'd recommend simplifying the whole thing to:
a[:] = a[k:] + a[:k]
If you swap two variables, there's no relation between two variables, then ok.
You can find the steps as following:
>>> a=[1,2,3,4,5]
>>> k=2
>>> # a[:k], a[k:] = a[k:], a[:k]
>>> x, y = a[k:], a[:k]
>>> a[:k] = x
>>> x, a
([3, 4, 5], [3, 4, 5, 3, 4, 5])
>>> a[k:] = y
>>> y, a
([1, 2], [3, 4, 1, 2])

The meaning of key function in sort() and the meaning of np.argsort()

I want to sort a List and get a return of its indices.
So I did it in two ways, but both of them give me the wrong result. I don't know, what the problem with that.
For example:
myList = [2, 1, 7, 3, 6]
My goal is to get the result: [1, 0, 4, 2, 3]
So the first method:
np.array(myList).argsort()
But I got the wrong result:
Out: array([1, 0, 3, 4, 2])
the second method:
indices = range[5]
indices.sort(key=myList.__getitem__)
I got the same wrong result:
Out: [1, 0, 3, 4, 2]
I have no idea, why this happens?
Here's your original list myList sorted against your expected list of indices vs the two results you got:
Excepted:
>>> [myList[each] for each in [1, 0, 4, 2, 3]]
[1, 2, 6, 7, 3]
Results from your solutions:
>>> [myList[each] for each in [1, 0, 3, 4, 2]]
[1, 2, 3, 6, 7]
I think your solutions are correct and your expected list is incorrect.
Update
Base on the explanation of the expected result actually being the "ranks" of each item in the input, here's a solution:
myList = [2, 1, 7, 3, 6]
def get_rankings(list):
return [sorted(list).index(each) for each in list]
print get_rankings(myList)
#[1, 0, 4, 2, 3]
I think you've misunderstood the description of what argsort() does. This method returns an array, where the value at each index, is the index in the original array of the element that belongs there.
For example:
[2, 1, 7, 3, 6]
becomes:
[1, 0, 3, 4, 2]
as in:
[1] - value = 1
[0] - value = 2
[3] - value = 3
[4] - value = 6
[2] - value = 7
Thanks all for the answer. I think, I misunderstood the index. But originally I really want to have this result: [1,0,4,2,3], not [1,0,3,4,2]
for myList [2, 1, 7, 3, 6]
2 is the second smallest number, corresponds to 1
1 is the first smallest number, corresponds to 0
7 is the fifth smallest number, corresponds to 4
3 is the third smallest number, corresponds to 2
6 is the fourth smallest number, corresponds to 3
So, that is why I expect [1,0,4,2,3]
I think, now I can get the result, just do following steps:
indices = np.array(myList).argsort()
[indices.tolist().index(i) for i in range(5)]
So I will get the expected result: [1,0,4,2,3]

remove duplicate element from a list, but only those who has odd number of duplicates

I am trying remove duplicate elements from the list, whose number of duplicates is odd.
For example for the following list: [1, 2, 3, 3, 3, 5, 8, 1, 8] I have 1 duplicated 2 times, 3 duplicated 3 times, and 8 duplicated 2 times. So 1 and 8 should be out and instead of 3 elements of 3 I need to leave only 1.
This is what I came up with:
def remove_odd_duplicates(arr):
h = {}
for i in arr:
if i in h:
h[i] += 1
else:
h[i] = 1
arr = []
for i in h:
if h[i] % 2:
arr.append(i)
return arr
It returns everything correctly: [2, 3, 5], but I do believe that this can be written in a nicer way. Any ideas?
You can use collections.Counter and list comprehension, like this
data = [1, 2, 3, 3, 3, 5, 8, 1, 8]
from collections import Counter
print [item for item, count in Counter(data).items() if count % 2]
# [2, 3, 5]
The Counter gives a dictionary, with every element in the input iterable as the keys and their corresponding counts as the values. So, we iterate over that dict and check if the count is odd and filter only those items out.
Note: The complexity of this solution is still O(N), just like your original program.
If order doesn't matter:
>>> a = [1, 2, 3, 3, 3, 5, 8, 1, 8]
>>> list(set([x for x in a if a.count(x)%2 == 1]))
[2, 3, 5]
The list comprehension [x for x in a if a.count(x)%2 == 1] returns only the elements which appear an odd number of times in the list. list(set(...)) is a common way of removing duplicate entries from a list.
you can possibly use scipy.stats.itemfreq:
>>> from scipy.stats import itemfreq
>>> xs = [1, 2, 3, 3, 3, 5, 8, 1, 8]
>>> ifreq = itemfreq(xs)
>>> ifreq
array([[1, 2],
[2, 1],
[3, 3],
[5, 1],
[8, 2]])
>>> i = ifreq[:, 1] % 2 != 0
>>> ifreq[i, 0]
array([2, 3, 5])

How to check if first list appear in the same order somewhere in the second list [duplicate]

This question already has answers here:
Check for presence of a sliced list in Python
(11 answers)
Closed 8 years ago.
Write a function called sublist. The function takes 2 lists as parameters, and returns True if the items in the first list appear in the same order somewhere in the second list (and False if they don't)
Here are some examples:
>>> sublist([2, 3], [1, 2, 3, 4, 5]) True
>>> sublist([1, 3], [1, 2, 3, 4, 5]) False
>>> sublist([1, 2, 3], [1, 2, 1, 2, 3, 4]) True
Here's what I have so far:
def sublist(list1,list2):
for i in range(len(list2)):
if list2[i] != list1[i]:
return False
return True
output:
>>> sublist([2,3],[1,2,3,4,5])
False
>>> sublist([1,3],[1,2,3,4,5])
True
>>> sublist([1,2,3],[1,2,1,2,3,4])
True
I know that's not entirely right and I know I'm going to have to use [ : ] to extract a portion of a string or a list but I have no idea where to start. Any help would be great, thank you.
Try this:
def sublist(list1, list2):
n = len(list1)
return any((list1 == list2[i:i + n]) for i in range(len(list2) - n + 1))
print sublist([2, 3], [1, 2, 3, 4, 5])
print sublist([1, 3], [1, 2, 3, 4, 5])
print sublist([1, 2, 3], [1, 2, 1, 2, 3, 4])
We need to know the length of the sublist, that's what n is for.
Then the any() will stop after the first match in the iterable. The part inside the any() is a generator, we're comparing the sublist (list1) with each of the sublists in list2, starting from the beginning up to the end.
i will range from 0 up to the length of the second list, but you subtract out the length of the first list and then add 1, so you don't go over the end of the index.

Categories