Check if preceding objects exist [closed] - python

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 10 months ago.
Improve this question
I need to write a method in Python to check that if a key is provided by the user, the preceding key must also be provided.
Example: If the user provides a list ['id_4','id_5','id_6'...], this will throw an error because the user did not provide the preceding keys, 'id_1','id_2','id_3'.
A valid list: ['id_1','id_2','id_3','id_4','id_5','id_6']
An invalid list: ['id_6'] (missing id_1 to id_5)
Note: this could be done with a dictionary or set, just curious if there are more elegant solutions out there.

If the preceding key must be in the list for each key, by recurrence this means that all key from the start must be present.
I think an ideal tool to validate this is a set:
def valid(l):
return set(l) == {f'id_{i}' for i in range(1, len(l)+1)}
# if you prefer to throw an exception, use
# assert set(l) == {f'id_{i}' for i in range(1, len(l)+1)}
valid(['id_4','id_5','id_6'])
# False
valid(['id_1','id_2','id_3','id_4'])
# True
IDs in order
If the IDs also need to be sorted, you can compare the pairs. For this itertools.pairwise can help (NB. pairwise requires python ≥ 3.10, for previous versions, check the recipe in the doc)
def valid(l):
return (l and l[0] == 'id_1'
and all(a+1 == b for a,b in
pairwise(int(x.rpartition('_')[-1])
for x in l))
)
valid(['id_4','id_5','id_6'])
# False
valid(['id_1','id_2','id_3','id_4'])
# True
valid(['id_1','id_3','id_2'])
# False

Cyclic sort if no duplicates are allowed
If you cannot use additional space (sets, dictionaries), then you can in-place sort, via cyclic sort.
This will be o(n) complexity with o(1) space.
Because element 1 -> n must be in a list of size n, we can assume if an item is greater than n, the list is not valid.
Then we can try and check for duplicates.
By the end, all elements 1-> n must be in the list of size n with no duplicates which satisfies your requirement. This solution is better than the dictionary/set approach as it uses no additional space.
def cyclicSort(l):
def getNumFromID(id):
return int(id[3:])
i = 0
while i < len(l):
correctIndex = getNumFromID(l[i]) - 1
if correctIndex > len(l):
return False
if i != correctIndex:
numberAtCorrectIndex = getNumFromID(l[correctIndex])
if numberAtCorrectIndex > len(l):
return False
if numberAtCorrectIndex != l[i]:
if l[correctIndex] == l[i]:
# duplicate found
return False
#swap the numbers after confirming neither are out of bounds
l[correctIndex], l[i] = l[i], l[correctIndex]
else:
i += 1
return True
print(cyclicSort(['id_1','id_2','id_3','id_4','id_5','id_6']))
print(cyclicSort(['id_1']))
print(cyclicSort(['id_6']))
print(cyclicSort(['id_2','id_3','id_4','id_5','id_6','id_1']))
print(cyclicSort(['id_1','id_2','id_3','id_4','id_5','id_5']))
Sorted list approach checking preceding elements##
If the list is already sorted, then
def checkPreceding(l):
id = 1
baseStr = "id_"
for idToCheck in l:
if idToCheck != baseStr + str(id):
return False
id += 1
return True
print(checkPreceding(['id_1','id_2','id_3','id_4','id_5','id_6']))
print(checkPreceding(['id_1']))
print(checkPreceding(['id_6']))
If the list is sorted, it's better to use checkPreceding approach since you will only need O(1) space.
However, if it is not sorted, you can use a dictionary/set for o(n) complexity with o(n) space or cyclic sort for o(1) space.

Related

Why is this code not valid for all the cases? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I am trying to solve this problem on hacker rank:
Here is my code:
L = []
check = True
num_cases = int(input())
for i in range(num_cases):
num_cubes = int(input())
inp = input()
L = inp.split(" ")
for m in range(0, len(L)):
L[m] = int(L[m])
while len(L) != 1:
x = max(L)
if L.count(x) <= 2:
if x == L[0] or x == L[-1]:
while x in L:
L.remove(x)
else:
check = False
break
else:
check = False
break
if check == False:
print("No")
else:
print("Yes")
L = []
check = True
Here I check if the maximum values of the list lie on either end of the list.
This code is working for all the cases that I have given it but works for none of the cases that the website gives it.
Test case 1: Here
Expected solution to test case 1: Here
PS. please inform me if I need to edit my question in any way.
the L.count(x) <= 2 is not correct, as long as it's at either end repeated number are fine e.g. 1 1 1 1 1 1 should be Yes
the while x in L bit is also incorrect, on two fronts
given 2 1 2 1 2 you're going to remove the 2 from the middle of the sequence, which should not be the case
not that this matters because you're also misunderstanding the behaviour of while... else, so this is never going to work either
finally the way you're going at it is extremely inefficient as you're traversing the entire sequence (looking for the max) on every iteration, with a double-ended queue (collections.deque) this can be solved in O(n):
define a "tip of stack" larger than anything possible (e.g. 231 or 232)
check which is the largest of the first or last of the row
if that is larger than your tip of stack, the row is not stackable
otherwise pop it (popleft/pop) and set it as the new tip of stack
then loop around to (2)
alternatively you can first pop the larger end of the row, then check against the current tip, then set as the new tip, same difference:
def solve(cubes):
"""
:param list(int) cubes: cube edge length
:rtype: bool
:returns: whether the input cubes can be stacked
"""
current = 2**32
cubes = collections.deque(cubes)
while cubes:
# pick largest value from either end
if cubes[0] > cubes[-1]:
val = cubes.popleft()
else:
val = cubes.pop()
# found a cube that's larger than the current top of the
# stack, can't solve
if val > current:
return False
current = val
return True
Also note that for this sort of things you might be well-served by:
separating the "parsing" step from the "resolution" step, this lets you more easily feed values and check results
learn about property-testing tools like hypothesis which can automatically generate and reduce test cases as long as you can define a property which should always hold (that's the hardest part)
You should remove if L.count(x) <= 2: , that is one error in your code's logic.

Printing to stdout gives the correct list, but appending to a list does not [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 years ago.
Improve this question
I working on this problem on leetcode:
Given a collection of distinct integers, return all possible permutations.
If I iteratively print my results I get the correct values. As soon as I add it to a list the results are incorrect. What is happening?
class Solution:
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
if len(nums) == 1:
return nums
permutations = list()
import math
max_swaps = math.factorial(len(nums))
pair = [0,1]
for i in range(max_swaps):
if pair[1] == len(nums):
pair[0] = 0
pair[1] = 1
p = self.swap(nums, pair[0], pair[1])
print("Adding %s to the list" % p)
permutations.append(p)
pair[0] += 1
pair[1] += 1
return permutations
def swap(self, nums, index1, index2):
tmp = nums[index2]
nums[index2] = nums[index1]
nums[index1] = tmp
return nums
I should get:
[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
But instead I get:
[[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3]]
You keep adding a reference to the same list to permutations.
When you call:
permutations.append(p)
Python doesn't take a copy of the list, it adds a reference. You only have one list.
What you want to do is:
permutations.append(p[:])
Which will take a copy.
When you return nums from swap, you're not making a copy, you're returning the same list that will be modified later. You can make a copy either at the return or when you append the list to your result.
This is a common bug in a lot of code. The bug you're seeing here is a symptom of having the values returned from swap be the same as nums. This means that you're appending nums over and over into the permutations list. If you were to print the entire permutations list instead of only p you'd see that they were always the same.
The solution is rather simple: At some point in your code (likely in swap or something) you need to make a copy of the nums list.

Extracting the subsequence of maximum length from a sequence [PYTHON] [duplicate]

This question already has an answer here:
Longest increasing unique subsequence
(1 answer)
Closed 6 years ago.
I have a sequence of values [1,2,3,4,1,5,1,6,7], and I have to find the longest subsequence of increasing length. However, the function needs to stop counting once it reaches a number lower than the previous one. The answer in this sequence in that case is [1,2,3,4]. As it has 4 values before being reset. How would I write the Python code for this?
Note: Finding the "longest increasing subsequence" seems to be a common challenge and so searching online I find a lot of solutions that would count for the entire length of the sequence, and return a subsequence of increasing values, ignoring any decrease, so in this case it would return [1,2,3,4,5,6,7]. That is not what I'm looking for.
It needs to count each subsequence, and reset the count upon reaching a number lower than the previous one. It then needs to compare all the subsequences counted, and return the longest one.
Thanks in advance.
Consider a function that generates all possible ascending subsequences, you would start with an empty list, add items until one element was less (or equal to?) the the previous at which point you save (yield) the subsequence and restart with a new subsequence.
One implementation using a generator could be this:
def all_ascending_subsequences(sequence):
#use an iterator so we can pull out the first element without slicing
seq = iter(sequence)
try: #NOTE 1
last = next(seq) # grab the first element from the sequence
except StopIteration: # or if there are none just return
#yield [] #NOTE 2
return
sub = [last]
for value in seq:
if value > last: #or check if their difference is exactly 1 etc.
sub.append(value)
else: #end of the subsequence, yield it and reset sub
yield sub
sub = [value]
last = value
#after the loop we send the final subsequence
yield sub
two notes about the handling of empty sequences:
To finish a generator a StopIteration needs to be
raised so we could just let the one from next(seq) propegate out - however when from __future__ import generator_stop is in
effect it would cause a RuntimeError so to be future compatible we
need to catch it and explicitly return.
As I've written it passing an empty list to
all_ascending_subsequences would generate no values, which may not
be the desired behaviour. Feel free to uncomment the yield [] to
generate an empty list when passed an empty list.
Then you can just get the longest by calling max on the result with key=len
b = [1,2,3,4,1,5,1,6,7]
result = max(all_ascending_subsequences(b),key=len)
print("longest is", result)
#print(*all_ascending_subsequences(b))
b = [4,1,6,3,4,5,6,7,3,9,1,0]
def findsub(a):
start = -1
count = 0
cur = a[0]
for i, n in enumerate(a):
if n is cur+1:
if start is -1:
start = i - 2
count=1
count+=1
cur = n
if n < cur and count > 1:
return [a[j] for j in range(start,start+count+1)]
print findsub(b)
A somewhat sloppy algorithm, but I believe it does what you want. Usually i would not have simply shown you code, but I suspect that is what you wanted, and I hope you can learn from it, and create your own from what you learn.
a slightly better looking way because I didn't like that:
b = [1,2,0,1,2,3,4,5]
def findsub(a):
answer = [a[0]]
for i in a[1:]:
if answer[-1] + 1 is i:
answer.append(i)
if not len(answer) > 1:
answer = [i]
elif i < answer[-1] and len(answer) > 1:
return answer
return answer
print findsub(b)
You need to do the following:
Create a function W that given a list, returns the index of the last item which is not strictly increasing from the start of the list.
For example, given the following lists: [1,2,3,4,1,2,3], [4,2,1], [5,6,7,8], it should return 4, 1, 4, respectively for each list
Create a variable maxim and set the value to 0
Repeatedly do the following until your list is empty
Call your function W on your list, and let's call the return value x
if x is greater than maxim
set maxim to x
At this point if you wish to store this sequence, you can use the list-slice notation to get that portion of your list which contains the sequence.
delete that portion of your list from the list
Finally, print maxim and if you were storing the parts of your list containing the longest sequence, then print the last one you got

Check whether an element occurs in a list using recursion [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
def check(x,num,i):
for n in range(len(x)):
if x[i] == num:
return True
else:
return(check(x,num,i+1))
return False
def User(x,num):
return(check(x,num,0))
User([2,6,1,9,7,3],5,0)
this should out put false since 5 is not in the list
checks whether an element occurs in a list recursively
so for example:
Input: a list L read from the keyboard, for example L = [2,6,1,9,7,3]
an element e, for example e = 9
but for some reason, i get an error when the number is not in the list
The beauty (and purpose) of recursion is that you do not need the loop:
def check(x, num, i):
if not x[i:]: # index past length
return False
if x[i] == num:
return True
return(check(x, num, i+1))
You can also do without the index parameter:
def check(x, num):
if not x:
return False
return x[0] == num or check(x[1:], num)
I don't exactly understand what you're doing, but this is a bizarre combination of recursion and iteration. If you're going to use recursion, it's worthwhile, at least for a basic recursive problem like this, to avoid iteration. Try something like this
def check(x, num, i = 0):
if i >= len(x):
return False
elif x[i] == num:
return True
else:
return check(x, num, i + 1)
This solution will work perfectly fine and is tail recursive so it will work quickly and optimally.
The way this works is it checks if the index, i, is out of bounds. If so, then it returns False. If it is in bounds, it checks if x[i] is equal to the number. If so, it returns True. If it is not, it returns check with the index increased and thus the recursion works.
First of all, your for loop doesn't make any sense. You never use that n and never go into the loop a second time, as you always return something in the first iteration. The return statement after the for loop is also unreachable, so your code could as well be
def check(x,num,i):
if x[i] == num:
return True
else:
return(check(x,num,i+1))
Then the actual issue is, that if you have a list with 5 elements for example, which does not contain the element searched for, you ask what the 6th is, although there is no 6th element, thus the error. You'd have to check whether the list contains 6 elements. So you check whether it has more than 5, return false if it does and continue if it doesn't. (Alternatively you could also check this at the start of the whole function)
def check(x,num,i):
if x[i] == num:
return True
else:
if len(num)>i:
return False
else:
return(check(x,num,i+1))
What you've done then is nothing but a overcomlicated, recursive for-Loop. You just increase i and compare, until you find the element or i is bigger than the list length. So this is equivalent to
def check(x,num):
for i in range(len(num)):
if x[i]==num:
return True
return False
It is very important that the return False is AFTER the for-Loop, as you only return, if you didn't find the element, even after iterating over the WHOLE list.
Also you can avoid indices. With a for-Loop you can directly iterate over the elements in a list:
def check(x,num):
for elem in num:
if elem==num:
return True
return False
This makes the variable elem become every element in you list, one after another.

Implementation of quick select in python. function is unstable and returns different values [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I tried to implement quick select to find the m'th smallest number in the list. When I run the program it returns the correct values sometime and incorrect values other times on the same array. What am I doing wrong her is the code
def select_mth_smallest(A, m):
pivot = np.random.choice(A)
# split into 3 partitions
A1 = []
A2 = []
A3 = []
for item in A:
if item < pivot:
A1.append(item)
if item > pivot:
A3.append(item)
else:
A2.append(item)
#find where m'th largest element is and recurse accordingly
if len(A1) >= m:
return select_mth_smallest(A1, m)
elif (len(A1) + len(A2)) >= m:
return pivot
else:
return select_mth_smallest(A3,m - (len(A1)+len(A2)))
Here is an input where the algorithm fails.
A = [1,2,3,4,5]
select_mth_smallest(A,5)
When I repeatedly execute this above statement I get, 5(correct) and 4(incorrect) alternatingly.
One thing that particularly baffles me (I am new to python) is that why I get different return values for the function when repeated with the same input. Looks rather sporadic.. BTW I am using Jupyter
You are adding some items to multiple partitions.
if item < pivot:
A1.append(item)
if item > pivot:
A3.append(item)
else:
A2.append(item)
A1 is the set of items less than the pivot. A3 is the set of items greater than the pivot. A2, however, is the set of items less than or equal to the pivot, because the 2nd if statement executes for all items, and one or the other branch will execute.
You want one, single if statement with an elif and else clause here.
if item < pivot:
A1.append(item)
elif item > pivot:
A3.append(item)
else:
A2.append(item)

Categories

Resources