Find the next available number in a python list - python

I have a list of integers that represent how many times an item has been used and I need to find the next number in the sequence that has been used the least amount of times (it might not even be in the list)
The amount of items is dynamic, the example uses 9 but that could be. Also, the amount of times it can appear is dynamic too.
We have X items, all of which are allowed to be used y times
Example.
We have 9 items, both of which are allowed to be used 2 times but should be used in order.
[1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2]
the above should return 3 as the next available item
[1, 2, 3, 4, 5]
the above should return 6 as the next available item
[1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9]
the above should return nothing, as there's no more available
I've already got me a function that's checking if the number appears at the max amount of uses
def is_item_available(item_number: int, uses: int, used_items: List):
"""Check if the item is available.
Args:
item_number (int): item number to be checked
uses (int): number of uses allowed
used_items (list): list of items currently used in a session
Returns:
bool: returns True if used item count is less than the uses number
"""
return used_items.count(item_number) < uses

I think this function works, if the numbers are guaranteed to be from 1-9:
def next_item(used_items):
if (used_items[-1] == 9 and len(used_items) == 18):
return "nothing"
elif (used_items[-1] == 9):
return 1
else:
return used_items[-1] + 1

Most optimal solution would be to use a min-heap to store the online data and fetch the top of the heap:
import collections, heapq
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2]
## Counter will maintain the count of each element in the list
counter = collections.Counter(lst)
## We now create a min-heap with (counter.count, list.val) as elements
heap = [(value, key) for key,value in dict(counter).items()]
## Now fetch the top element from the min-heap. By definition, this would correspond to the minimum list.val with minimum count
smallest_element = heapq.nsmallest(1, heap)
## If the list.val is already been used twice, return "None" else return the list.val
if smallest_element[0] > 1:
return None
return smallest_element[1]

Related

my list value changing incorrectly - python

im trying to generate mastercard card number.
requirements :
first element must be 5
second element must be between 1 and 5
last element must be lcheck digit returned from luhn algorithm.
i have check digit function with luhn algorithm, so far everything is okay.
but when i give parameter my card number to generateCheckDigit function in generateMasterCard function, my card number is returned as multiplied by 2, one element apart during the luhn algorithm.
sorry for my bad english
here is the codes:
def generateCheckDigit(numbers):
if len(numbers)%2 == 1:
for i in range(0,len(numbers),2):
numbers[i] *= 2
else:
for i in range(1,len(numbers),2):
numbers[i] *= 2
check_digit = (sum(numbers)*9) % 10
return check_digit
def generateMasterCard():
card_number = [5, rd.randint(1,5)]
for i in range(13):
card_number.append(rd.randint(0,9))
print(f"first number : {card_number}")
check_digit = generateCheckDigit(card_number)
card_number.append(check_digit)
return card_number
output :
first number : [5, 4, 1, 4, 0, 8, 4, 8, 0, 4, 2, 8, 8, 2, 9]
[10, 4, 2, 4, 0, 8, 8, 8, 0, 4, 4, 8, 16, 2, 18, 4]
You can import copy and use generateCheckDigit(copy.copy(card_number)) as
Alexey Larionov sais in comments "In Python if you pass to a function some complicated value, like class instance, list, dictionary, etc, then your function can freely modify it. In your case, you do operation numbers[i] *= 2 and it changes the list you passed". Passing a copy allows you to avoid this.

How to access list of arbitrary depth?

I have a list known as data which can be any depth equal to or greater than 1.
e.g;
Sometimes data = [3,65,3]
or data = [[3,65,3],[88,44,9],[6,2,21]] ... and so on.
How would I generally access data, considering it's depth can fluctuate? It's assumed that the depth and indexes to access an element (a number) will always be known.
I.e.
Say I have a function f that takes arbitrary arguments. How would I generalize the following?
f(a , b, c...)
if depth = 1:
return data[a]
elif depth = 2:
return data[a][b]
elif depth = 3:
return data[a][b][c]
...
and so on
You can iteratively access sublists based on the number of indices you provide, which implicitly means that's the depth. You can further make checks for the legality of the arguments if you don't trust the user to always provide valid indices.
def f(*indices):
element = data
for index in indices:
element = element[index]
return element
You can also edit the value at some index, which will be done in place.
def f(indices, value):
if not len(indices):
return
element = data
for index in indices[:-1]:
element = element[index]
element[indices[-1]] = value
indices is supposed to be a loop, so you'd be expected to call it as f((1, 1), 5). If instead you would prefer to call it as f(1, 1, 5), where all the arguments are the indices and the ast one is the new value, then change the function to
def f(*args):
indices, value = args[:-1], args[-1]
# then the same as above
Considering your input would be like this:
data = [[3,65,3],[88,44,[9, 4, 56]],[6,2,21]]
you can flatten it like this:
def flatten(l):
r = []
for e in l:
if isinstance(e, list):
r += flatten(e)
else:
r.append(e)
return r
OUTPUT:
>>> flatten([[3,65,3],[88,44,[9, 4, 56]],[6,2,21]])
[3, 65, 3, 88, 44, 9, 4, 56, 6, 2, 21]
Another recursive solution using generators:
def flatten(s):
if not isinstance(s, list):
yield s
else:
for i in s:
for b in flatten(i):
yield b
print(list(flatten([[3,65,[3, [[5, 6, [2, 6, [4]]]]],[88,44,[9, 4, 56]],[6,2,21]]])))
Output:
[3, 65, 3, 5, 6, 2, 6, 4, 88, 44, 9, 4, 56, 6, 2, 21]

How is sorted(key=lambda x:) implemented behind the scene?

An example:
names = ["George Washington", "John Adams", "Thomas Jefferson", "James Madison"]
sorted(names, key=lambda name: name.split()[-1].lower())
I know key is used to compare different names, but it can have two different implementations:
First compute all keys for each name, and bind the key and name together in some way, and sort them. The p
Compute the key each time when a comparison happens
The problem with the first approach is that it has to define another data structure to bind the key and data. The problem with the second approach is that the key might be computed for multiple times, that is, name.split()[-1].lower() will be executed many times, which is very time-consuming.
I am just wondering in which way Python implemented sorted().
The key function is executed just once per value, to produce a (keyvalue, value) pair; this is then used to sort and later on just the values are returned in the sorted order. This is sometimes called a Schwartzian transform.
You can test this yourself; you could count how often the function is called, for example:
>>> def keyfunc(value):
... keyfunc.count += 1
... return value
...
>>> keyfunc.count = 0
>>> sorted([0, 8, 1, 6, 4, 5, 3, 7, 9, 2], key=keyfunc)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> keyfunc.count
10
or you could collect all the values that are being passed in; you'll see that they follow the original input order:
>>> def keyfunc(value):
... keyfunc.arguments.append(value)
... return value
...
>>> keyfunc.arguments = []
>>> sorted([0, 8, 1, 6, 4, 5, 3, 7, 9, 2], key=keyfunc)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> keyfunc.arguments
[0, 8, 1, 6, 4, 5, 3, 7, 9, 2]
If you want to read the CPython source code, the relevant function is called listsort(), and the keyfunc is used in the following loop (saved_ob_item is the input array), which is executed before sorting takes place:
for (i = 0; i < saved_ob_size ; i++) {
keys[i] = PyObject_CallFunctionObjArgs(keyfunc, saved_ob_item[i],
NULL);
if (keys[i] == NULL) {
for (i=i-1 ; i>=0 ; i--)
Py_DECREF(keys[i]);
if (saved_ob_size >= MERGESTATE_TEMP_SIZE/2)
PyMem_FREE(keys);
goto keyfunc_fail;
}
}
lo.keys = keys;
lo.values = saved_ob_item;
so in the end, you have two arrays, one with keys and one with the original values. All sort operations act on the two arrays in parallel, sorting the values in lo.keys and moving the elements in lo.values in tandem.

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.

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