pick cards (fewer cards ,cost less) - performance issue - python

n - number of cards in hand eg : n = 4
collection - cards collection as per n eg: collection =[1,3,4,7]
d denotes total cards eg: 10 [1,2,3,4,5,6,7,8,9,10]
Card 1-cost 1 ; card 5-cost 5
Scenario : need to pick cards not in the collection list and the card cost less than (d) and maximum no of possible cards need to show
eg: sum of (2+5) <10 so we need to show (fewer cards ,cost less) accepted
eg: sum of (2+6) < 10 rejected (fewer cards ,cost more)
eg: sum of (2+5+6) < 10 rejected (more cards ,cost more,count more than d)
eg: sum of (2+8) < 10 rejected (cost more)
it working fine for small data getting performance issue:
Scenario 1:
start = time. time()
n=4
collection=[1,3,4,7]
d=10
lis=[]
list1=[]
[lis.append(x+1) for x in range(0,d)]
[lis.remove(x) for x in collection]
#print(lis)
#for L in range(0, len(lis)+1):
for subset in itertools.combinations(lis, d%n):
if sum(subset)<=d:
#print(subset)
list1.append(subset)
k = list(map(lambda x: len(x),list1))
s = list(filter (lambda x: len(x)==max(k),list1))
m = list(filter(lambda x: sum(x) == min(list(map(lambda x: sum(x),s))),s))
print(*m[0],sep='\n')
end = time. time()
print(end - start)
Result:
2 5
time 0.0
scenario 2 : n=8 collection=[1,3,4,7,20,25,50,60] d=100
Result
2
5
6
8
Time:762.9762706756592

If I understand your problem correctly, I think this does something like what you want:
def pick_cards(collection, d):
collection_set = set(collection)
# The ordered sequence of cards not in collection
pickable = (i for i in range(1, d + 1) if i not in collection_set)
# Sum of picked cards
s = 0
# Picked cards
picked = []
for pick in pickable:
# If the card does not go over the limit
if s + pick < d:
# Add card
picked.append(pick)
s += pick
else:
# Otherwise finish
break
return picked
# Examples
print(pick_cards([1, 3, 4, 7], 10))
# [2, 5]
print(pick_cards([1, 3, 4, 7, 20, 25, 50, 60], 100))
# [2, 5, 6, 8, 9, 10, 11, 12, 13, 14]

Related

Check if variable changes in for loop in Python

I have this code here and I'm looking for a way to check if min_score and max_score changes, and count how many times it changes. I can't seem to find a way to do it:
games = int(input())
score = list(input().split())
score = [int(x) for x in score]
for y in range(1, len(score) + 1):
min_score = (str(min(score[:y])) + " MIN")
max_score = (str(max(score[:y])) + " MAX")
print(min_score)
print(max_score)
This is a sample test case for reference:
9
10 5 20 20 4 5 2 25 1
First number is the size of the array, which in my code I never use because I make an array just from the string of numbers below ( in fact I don't even know why they give the size).
Basically I need to find how many times the max and min values change. I'm still a beginner in programming and I don't really know what to do..
you could just keep track of the lowest and highest number encountered and check if the current score is just below or above. A simple script could look like this:
scores = [10,5,20,20,4,5,2,25,1]
countChanges = 0
limitLow = float("inf")
limitHigh = -float("inf")
for s in scores:
if(s < limitLow):
countChanges += 1
limitLow = s
if(s > limitHigh):
countChanges += 1
limitHigh = s
print("current score: %3d limits: [%2d .. %2d] changes:%d" % (s, limitLow, limitHigh, countChanges))
spam = [10, 5, 20, 20, 4, 5, 2, 25, 1]
print(sum(n < min(spam[:idx]) for idx, n in enumerate(spam[1:], start=1)))
print(sum(n > max(spam[:idx]) for idx, n in enumerate(spam[1:], start=1)))
output
4
2
if you also want to account for initial value - add 1.
Looks like a hankerrank problem? They often give the length of the input to allow solutions without knowing about built-in methods like len().
Anyway,
You can initialise min and max to the first element of the array (if it exists, check the specification), or some suitably small and large values (again, check the possible values).
Then you can count the number of times min and max changes as you go.
Should be easy enough to adapt for the case that you just want to track any change, not min and max separately. It wasn't clear from your question.
scores = [10, 5, 20, 20, 4, 5, 2, 25, 1]
min_score = scores[0]
max_score = scores[0]
min_score_changes = 0
max_score_changes = 0
for score in scores:
if score < min_score:
min_score = score
min_score_changes += 1
if score > max_score:
max_score = score
max_score_changes += 1
I solved it like this after some thinking:
games = int(input())
score = list(input().split())
score = [int(x) for x in score]
min_score_list, max_score_list = [] , []
for y in range(1, len(score) + 1):
min_score = (min(score[:y]))
max_score = (max(score[:y]))
if min_score not in min_score_list:
min_score_list.append(min_score)
if max_score not in max_score_list:
max_score_list.append(max_score)
print((len(max_score_list) - 1), len(min_score_list) - 1)
I know it's not perfect code but at least I did myself :D

List indexes - If too big go back to the beginning of the list

So, maybe this question will sound very beginnerish, but I just don't know how I should begin with this example:
So the example is:
I have a list for example 13 items long (1,2,3,4...13)
There's a given number, let's say 6
The program needs to show me in a list, in what order are the numbers going to fall out. If the second number is 6, it means every time the sixth item is the next whcih is going to fall out. But my problem is that how could I tell python that if the index number goes up too high, it should start counting again from the beggining?
This is what I made myself so far
x = int(input("Number of items (numbers): "))
y = int(input("Fall-out number: "))
#n = 1
#id = 0
numbers = [n for n in range(x+1)]
fallsout = []
numbers.remove(30)
for i in numbers:
if i % y == 0:
fallsout.append(i)
print (numbers)
print (fallsout)
Here's an example what should be in the input and output:
Input:
x = 13
y = 6
Output: 6 12 5 13 8 3 1 11 2 7 4 10 9
Okay, looks like you want to copy every 6th element from numbers into fallout and then remove the element from numbers, and continue on in a cyclic fashion until numbers is empty.
import copy
x = int(input("Number of items (numbers): "))
y = int(input("Fall-out number: "))
# list should start from 1 as by the example
numbers = [n for n in range(1,x+1)]
# deep copy to preserve original list
numbers_copy = copy.deepcopy(numbers)
fallsout = []
count = y
while len(numbers_copy)!=0:
fallsout.append(numbers_copy[count-1])
# remove element
del numbers_copy[count-1]
# handle starting edge
if count == 0:
count = 1
# handle last edge
if numbers_copy != []:
count = (count+y-1)%len(numbers_copy)
print numbers
print fallsout
Output is
Number of items (numbers): 13
Fall-out number: 6
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
[6, 12, 5, 13, 8, 3, 1, 11, 2, 7, 4, 10, 9]
Explanation:
Suppose I have a array numbers = [1,2,3,4,5,6] of length=6, and I am using an counter "count" to iterate through the list. So that,
numbers[count] = 2 (when count=1)
Then to look at the next element, I would use numbers[count+1].
To jump back to the starting of the list, we use modulus operation,
count = (count+number_of_steps)%len(numbers)
eg, at index=4 and to jump 3 steps, next index would be (4+3)%6 = 1
Now we have to copy every yth element from the list,so we use,
fallsout.append(numbers_copy[count-1]) # count-1 as we are counting from 0
Then we remove that number from the list,
del numbers_copy[count-1]
Then we jump forward count by y steps by modulus as discussed above,
count = (count+y-1)%len(numbers_copy) # again -1 as we count from 0
The length of numbers needs to be calculated again as the list could change due to deleting of elements.

Credit card validation - returning values that aren't hard coded

How do I compute the answer so that the answer is not a hard-coded solution? Like if I wanted to put in another credit card number how can I return the result of that new credit card? Also how can I create one x list rather then the way I have it now with the values split up by 2?
Also here is the original question for reference:
Credit card numbers are validated using Luhn’s formula 3. Implement a program that takes a credit card numbers as a multidimensional array (you may assume it consists of exactly of 16 columns), and returns a list with values Valid if it is a valid card number, and Invalid otherwise.
One way to perform the validity test is as follows:
1. From the rightmost digit, which is the check digit, moving left, double the value of every second digit; if the product of this doubling operation is greater than 9 (e.g., 8 2 = 16), then sum the digits of the products (e.g.,16: 1 + 6 = 7, 18: 1 + 8 = 9).
2. Take the sum of all the digits.
3. If the total is divisible by 10, then the number is valid according to the Luhn formula; else it is not valid.
Note: You can maniplulate card numbers either as strings (using indexing and slicing to extract digits, etc) or as integers (using integer division and remainder to manipulate digits).
My script:
import numpy as py
x = [[7,1],[6,3],[4,5],[6,2],[7,8],[3,4],[6,8],[3,9]] #credit card numbers
x2 = np.array(x)
evryothernum = x2[:,1] #returns every other number / every seconds digit
evryothernum2 = np.multiply(evryothernum,2)
sumdigits = []
def card_validate(x):
evryothernum = x2[:,1] #valid
evryothernum2 = np.multiply(evryothernum,2) #multiplys evryothernum by 2
b=np.sort(evryothernum2, axis = None) #sorts the evryothernum2 array in order
b2 = np.array(b)
b3 = b2[4:8] #shows the highest values aka greater than 9
b3
b3 = [1,7,7,9]
newb3 = np.sum(b3)
newx2 = np.sum(x2[:,0])
total = np.sum(newb3+newx2)
if ( (total % 10) == 0 ):
print "Valid"
else:
print "Invalid"
return card_validate()
Is there an easier way then to do this without Numpy?
The following can be used to implement the logic without using numpy
a=[[4,0,1,2,8,8,8,8,8,8,8,8,1,8,8,1],[4,0,1,2,8,8,8,8,8,8,8,8,1,8,8,2]] #array of credit card numbers
def validate(creditcard_numbers,tmp):
even_index=-1
for j in range(0,16):
sum_val=0
if even_index%2 ==0: #index calculation for even indices
val=creditcard_numbers[even_index]*2
if val>9: # add the digits if the value got after multiplying by 2 is two digit number
while val !=0:
rem=val%10
val=val/10
sum_val=sum_val+rem
tmp[even_index]=sum_val #append the temporary list with the new values which is got by adding the digits if the result of multiplying by 2 is a 2 digit number
else:
tmp[even_index]=val
else:
tmp[even_index]=creditcard_numbers[even_index]
even_index=even_index-1
total=0
for i in tmp:
total=total+i
if total%10 == 0:
return "valid"
else:
return "invalid"
for creditcard_numbers in a:
print creditcard_numbers
tmp=[0]*len(creditcard_numbers) #temporary list with zeros's
result=validate(creditcard_numbers,tmp)
print result
**OUTPUT :
[4, 0, 1, 2, 8, 8, 8, 8, 8, 8, 8, 8, 1, 8, 8, 1]
valid
[4, 0, 1, 2, 8, 8, 8, 8, 8, 8, 8, 8, 1, 8, 8, 2]
invalid
**
Here's a couple of ways. The first is a straight port to Python of the pseudo-code on the "Luhn algorithm" Wikipedia page (link). The second uses a lookup table to with the pre-computed doubled value of every other digit:
def checkLuhn(purportedCC):
sm = 0
nDigits = len(purportedCC)
parity = nDigits % 2
for i in range(nDigits):
digit = int(purportedCC[i])
if i % 2 == parity:
digit = digit * 2
if digit > 9:
digit = digit - 9
sm = sm + digit
return (sm % 10) == 0
def check(s):
lookup = [0,2,4,6,8,1,3,5,7,9]
digits = [int(c) for c in reversed(s)] # count odd/even from the right
odd = digits[::2]
even = digits[1::2]
total = sum(odd) + sum(lookup[c] for c in even)
return total % 10 == 0
cards = '1111222233334444','1111222233334445','01111222233334444'
for card in cards:
print(card,check(card))
print(card,checkLuhn(card))
Output (note if done correctly leading zeros don't affect the validation):
1111222233334444 True
1111222233334444 True
1111222233334445 False
1111222233334445 False
01111222233334444 True
01111222233334444 True

Sorting 3 piles of numbers row by row left to right

Hey I need to sort out 3 lists in a special way after they have been mixed up and placed like in a deck row by row (Link to the full question):
a=[1,2,3]
b=[4,5,6]
c=[7,8,9]
Now the order is b, a, c and you have to place all of the numbers from left to right (I need to do this for a deck so the numbers will contain letters next to them making them a string).
Expected outcome:
a = [4,1,7]
b = [5,2,8]
c = [6,3,9]
*Note the lists that I am working on contain more than 3 values in them
Just zip them:
>>> a=[1,2,3]
>>> b=[4,5,6]
>>> c=[7,8,9]
>>> a, b, c = map(list, zip(b, a, c)) # in the order specified: b, a, c
>>> a
[4, 1, 7]
>>> b
[5, 2, 8]
>>> c
[6, 3, 9]
It would also work with (but that changes the lists in-place):
>>> a[:], b[:], c[:] = zip(b, a, c)
Instead of the map(list, ...).
In case you have more values and want to distribute them:
>>> a=[1,2,3,4]
>>> b=[5,6,7,8]
>>> c=[9,10,11,12]
>>> tmp = b + a + c # concatenate them in the order
>>> # distribute them: every third element, starting with 0 (a), 1 (b) and 2 (c)
>>> a, b, c = tmp[::3], tmp[1::3], tmp[2::3]
>>> a
[5, 8, 3, 10]
>>> b
[6, 1, 4, 11]
>>> c
[7, 2, 9, 12]
Once the selected pile has been picked, you need to put the selected pile in the middle of the other two piles. One option would be just to combine the three different pile lists into one list, with the chosen pile in the middle.
if pile == 1: NewCards = Pile2 + Pile1 + Pile3
elif pile == 2: NewCards = Pile1 + Pile2 + Pile3
else: NewCards = Pile1 + Pile3 + Pile2
EDIT:
Okay, so you need to deal out the combination of the cards into 3 piles. You can loop through each of the decks, and deal them out. Make sure the right deck is in the middle! (In this case I'll use deck 2).
# create three empty temporary lists
temp = [[],[],[]]
cardnum = 0
# loop through the 3 decks
for i in range(3):
if i == 0: deck = partA
elif i == 1: deck = partB
else: deck = partC
# loop through the cards in the decks
for card in deck:
i = cardnum % 3 # mod 3 to split the cards among the decks
temp[i] += card
cardnum += 1
# update the decks now
partA = temp[0]
partB = temp[1]
partC = temp[2]
Hmmm .... an interesting problem :P
I am going to do some thing which i hate when people do to me... post code...
See if there is something here that helps you.
HINT HINT: Have a look at the get_order function.
from itertools import product, izip_longest
import random
def grouped(iterable, n, fillvalue=None):
return izip_longest(fillvalue=fillvalue, *[iter(iterable)] * n)
def get_order(selected, seq=[0,1,2]):
seq = [i for i in seq if i!=selected]
seq.insert(len(seq)/2, selected)
return seq
deck = ['-'.join(card) for card in product('c h d s'.split(), 'a 1 2 3 4 5 6 7 8 9 10 j q k'.split())]
plycards= random.sample(deck,21)
piles = [[],[],[]]
for idx, i in enumerate(grouped(plycards, 3)):
for idx, item in enumerate(i):
piles[idx].append(item)
print (i)
for j in range(0,3):
# Combine again
plycards = []
for i in get_order(int(raw_input('Which pile? '))-1):
plycards += piles[i]
print ('-------------')
piles = [[],[],[]]
for idx, i in enumerate(grouped(plycards, 3)):
for jdx, item in enumerate(i):
piles[jdx].append(item)
print (i)
print ("You selected card :'{}'".format(plycards[10])

Adding numbers in a list but only after a certain number

I'm writing a script that takes a bowling score.
The Rules
-If you get a STRIKE you get 10 points plus the next two balls you score.
My question: Is there a way to add the next two numbers in a list after 10 appears. so far my code just takes the users score and stores it in a list.
def f54():
total_pins= 10
max_score= 300
frames= 20
count= 1
score=0
zval = []
yval = []
for i in range(1,11):
2_ahaed = i+2
1_ahead = i+1
z=int(input('What was your score for ball 1 frame ' +str(i)+':'))
if z != 10:
y=int(input('What was your score for ball 2 frame ' +str(i)+':'))
if z > total_pins:
print('this number is too large, re enter all scores')
f54()
if z < 10:
zval.append(z)
if z == 10:
print('Strike!')
if y > total_pins:
print('this number is too large, re enter all scores')
f54()
if y < 10:
yval.append(y)
if y == 10-z:
print('spare!')
I am not too familiar with bowling scoring rules but this should do what you are asking:
scores = [1,2,10,3,4,5,10,1]
ret = [0 for x in (scores)]
for i in xrange(len(scores)):
ret[i] = sum(scores[i:i+3]) if scores[i] == 10 else scores[i]
print "Final score", sum(ret)
Yes You can. .
List[index:] represents all of the values that comes After the given index number. .
List[:index] represents all of the values that comes Before the given index number. .
in this Case,
zval = [1, 2, 3, 4, 5, 6, 7, 8, 9]
for val in zval:
if val==7:
`print zval[val:]`
print sum(zval[val:])

Categories

Resources