I'm trying to find out if the following poker hand is a flush:
In the first case I analyse 5 cards. A flush is true if there all the 5 suits are identical (C H D S), i.e. there is only one suit present. That works fine.
a=['AC', '3H', 'TD', '9C', 'KD']
flush = len({suit for _, suit in a}) ==1 #false
In reality however there are usually 7 cards. 2 are held by the player and 5 are on the table. Here it gets a bit more complicated. How can I check if any suit occurs exactly 5 times?
b=['AC', '3H', 'TD', '9C', 'KD', '7H', '5S']
flush = ?
Speed is very important as this is part of an inner loop of a montecarlo simulation, so this should probably be a one-liner if possible.
You could use count and max to find... well, the max count of any of the suits and see whether it's at least 5.
>>> b = ['AC', '3H', 'TD', '9C', 'KD', '7H', '5S']
>>> suits = [s for _, s in b]
>>> max(suits.count(s) for s in suits) >= 5
False
But this will loop the list of suits for each element of that list, giving it O(n^2) complexity. Probably not too bad, considering that n is just 7, but still. Or use collections.Counter. This should be much faster (O(n)), as it uses a dictionary to keep track of the counts.
>>> max(collections.Counter((s for _, s in b)).values())
2
>>> collections.Counter((s for _, s in b)).most_common(1)
[('H', 2)]
list = ['AC', '3H', 'TD', '9C', 'KD']
substring='C'
print( len([s for s in list if substring in s]))
If speed is the key, well, there are only 7 cards, 4 suits. That makes 16384 combinations. I would convert each combination to a number and make a lookup in a precomputed table using this number as an index.
CONV = dict(C=0, H=1, D=2, S=3)
def flush_table_index(cards):
n = 0
for _, s in cards:
n = n * 4 + CONV[s]
return n
Edit: if-elif-elif instead of CONV would be quicker. Not a pretty or interesting code though.
Related
I have about 20 short strings that I want to permutate. I want only permutations that have len == 8.
I would like to avoid calculating every possible permutation, as seen below:
import itertools
p = itertools.permutations([s1, s2, s3, s4, s5, s6,...])
for i in p:
s = ''.join(j for j in i)
if len(s)==8:
print(s)
But that's too slow right? How can I decrease the number of calculations? (to not spend processing and RAM).
The first, obvious thing to do is filter out any strings with length > 8:
newList = [i for i in [s1, s2, s3, s4, s5, s6, ...] if len(i) <= 8]
Then, you can use the second argument of itertools.permutations to set the number of items you want. If you have no empty strings in your list, you'll never need more than 8 items, so we can use 8 as the second argument:
p = itertools.permutations(newList, 8)
However, if any of your strings are longer than one character, this won't get you what you want, since it will only return permutations of exactly 8 items. One way to resolve this is to iterate through the various lengths:
pList = [itertools.permutations(newList, length) for length in range(1, 9)]
Yet here you end up with an enormous amount of permutations to filter through: P(20, 8) + P(20, 7) + ... P(20, 1) = roughly 5.5 billion, which is impractical to work with.
A different direction
Instead of using permutations, let's use combinations, of which there are far fewer ("only" 263,949). Recall that in combinations, the order of the combined items doesn't matter, while in permutations it does. Thus we can use the smaller set of combinations to filter for the length 8 that we want:
cList = (combo for length in range(1, 9)
for combo in itertools.combinations(newList, length)
if len(''.join(combo)) == 8)
Using () instead of [] will make this a generator rather than a list, to delay evaluation until we really need it. And now we are close!
We can get our final result by taking the permutations of the items in cList:
result = [''.join(perm) for combo in cList
for perm in itertools.permutations(combo)]
Could you give me a hint where the time consuming part of this code is?
It's my temporary solutions for the kata Generate Numbers from Digits #2 from codewars.com.
Thanks!
from collections import Counter
from itertools import permutations
def proc_arrII(arr):
length = Counter(arr).most_common()[-1][1]
b = [''.join(x) for x in list(set(permutations(arr,length)))]
max_count = [max(Counter(x).values()) for x in b]
total = 0
total_rep = 0
maximum_pandigit = 0
for i in range(len(b)):
total+=1
if max_count[i] > 1:
total_rep+=1
elif int(b[i]) > maximum_pandigit:
maximum_pandigit = int(b[i])
if maximum_pandigit == 0:
return([total])
else:
return([total,total_rep,maximum_pandigit])
When posting this,
it would have been helpful to offer example input,
or link to the original question,
or include some python -m cProfile output.
Here is a minor item, it inflates the running time very very slightly.
In the expression [''.join(x) for x in list(set(permutations(arr, length)))]
there's no need to call list( ... ).
The join just needs an iterable, and a set works fine for that.
Here is a bigger item.
permutations already makes the promise that
"if the input elements are unique, there will be no repeat values in each permutation."
Seems like you want to dedup (with set( ... )) on the way in,
rather than on the way out,
for an algorithmic win -- reduced complexity.
The rest looks nice enough.
You might try benching without the elif clause,
using the expression max(map(int, b)) instead.
If there's any gain it would only be minor,
turning O(n) into O(n) with slightly smaller coefficient.
Similarly, you should just assign total = len(b) and be done with it,
no need to increment it that many times.
The task is:
User enters a number, you take 1 number from the left, one from the right and sum it. Then you take the rest of this number and sum every digit in it. then you get two answers. You have to sort them from biggest to lowest and make them into a one solid number. I solved it, but i don't like how it looks like. i mean the task is pretty simple but my code looks like trash. Maybe i should use some more built-in functions and libraries. If so, could you please advise me some? Thank you
a = int(input())
b = [int(i) for i in str(a)]
closesum = 0
d = []
e = ""
farsum = b[0] + b[-1]
print(farsum)
b.pop(0)
b.pop(-1)
print(b)
for i in b:
closesum += i
print(closesum)
d.append(int(closesum))
d.append(int(farsum))
print(d)
for i in sorted(d, reverse = True):
e += str(i)
print(int(e))
input()
You can use reduce
from functools import reduce
a = [0,1,2,3,4,5,6,7,8,9]
print(reduce(lambda x, y: x + y, a))
# 45
and you can just pass in a shortened list instead of poping elements: b[1:-1]
The first two lines:
str_input = input() # input will always read strings
num_list = [int(i) for i in str_input]
the for loop at the end is useless and there is no need to sort only 2 elements. You can just use a simple if..else condition to print what you want.
You don't need a loop to sum a slice of a list. You can also use join to concatenate a list of strings without looping. This implementation converts to string before sorting (the result would be the same). You could convert to string after sorting using map(str,...)
farsum = b[0] + b[-1]
closesum = sum(b[1:-2])
"".join(sorted((str(farsum),str(closesum)),reverse=True))
Hi Guys For my Data Structure assignment I have to find the most efficient way (big-o wise) to calculate permutations of a list of objects.
I found recursive examples on the web but this doesn't seem to be the most efficient way; I tried my own code but then I realized that when I count the number of possible permutations I'm actually making my algorithm O(!n). Any suggestions? .-.
from random import sample
import time
start = time.time()
testList = list(x for x in range(7))
print('list lenght: %i objects' % len(testList))
nOfPerms = 1
for i in range(1,len(testList)+1):
nOfPerms *= i
print('number of permutations:', nOfPerms)
listOfPerms = []
n = 1
while n <= nOfPerms:
perm = tuple(sample(testList, len(testList)))
listOfPerms.append(perm)
permutations = set(listOfPerms)
if len(permutations) == len(listOfPerms):
n += 1
else:
del(listOfPerms[-1])
end = time.time() - start
print('time elapsed:', end)
OUTPUT:
list lenght: 7 objects
number of permutations: 5040
time elapsed: 13.142292976379395
If instead of 7 I put 8 or 9, or 10, those are the number of permutations (I won't show the time cause it's taking too long):
list lenght: 8 objects
number of permutations: 40320
list lenght: 9 objects
number of permutations: 362880
list lenght: 10 objects
number of permutations: 3628800
I believe this will be the best you can do. Generating the number of permutations of a list generates n! permutations. As you need to generate them all this is also how much time it will take (O(n!)). What you could try to do is to make it a python generator function so you will always only generate exactly as many as you need instead of precalculating them all and storing them in memory. If you want an example of this i could give you one.
Im sorry this might be a quite negative answer. It's a good question but im pretty sure this is about the best that you can do, asymptotically. You could optimize the code itself a bit to use less instructions but in the end that wont help too much.
Edit:
This is a python implementation of Heap's algorithm which i promised
(https://en.wikipedia.org/wiki/Heap%27s_algorithm) generating N! permutations where the generation of every one permutation takes amortized O(1) time and which uses O(n) space complexity (by alteri
def permute(lst, k=None):
if k == None:
k = len(lst)
if k == 1:
yield lst
else:
yield from permute(lst, k-1)
for i in range(k-1):
if i % 2 == 0:
#even
lst[i], lst[k-1] = lst[k-1], lst[i]
else:
#odd
lst[0], lst[k-1] = lst[k-1], lst[0]
yield from permute(lst, k-1)
for i in permute([1, 2, 3, 4]):
print(i)
I'm working on my final for a class I'm taking(Python 3) im stuck at this part.
he gave us a file with numbers inside of it. we opened it and add those numbers to a list.
"Create a function called makeOdd() that returns an integer value. This function should take in any integer and reduce it down to an odd number by dividing it in half until it becomes an odd number.
o For example 10 would be cut in half to 5.
o 9 is already odd, so it would stay 9.
o But 12 would be cut in half to 6, and then cut in half again to 3.
o While 16 would be cut to 8 which gets cut to 4 which gets cut to 2 which gets cut to 1.
Apply this function to every number in the array. "
I have tried to search the internet but i have not clue where to even begin with this one. any help would be nice.
Here my whole final so far:
#imports needed to run this code.
from Final_Functions import *
#Defines empty list
myList = []
sumthing = 0
sortList = []
oddList = []
count = 0
#Starts the Final Project with my name,class, and quarter
intro()
print("***************************************************************",'\n')
#Opens the data file and reads it then places the intrager into a list we can use later.
with open('FinalData.Data', 'r') as f:
myList = [line.strip() for line in f]
print("File Read Complete",'\n')
#Finds the Sum and Adverage of this list from FinalData.Data
print("*******************sum and avg*********************************")
for oneLine in myList:
tempNum = int(oneLine)
sumthing = sumthing + tempNum
avg = sumthing /1111
print("The Sum of the List is:",sumthing)
print("The Adverage of the List is:",avg,'\n')
print("***************************************************************",'\n')
#finds and prints off the first Ten and the last ten numbers in the list
firstTen(myList)
lastTen(myList)
print("***************************************************************",'\n')
#Lest sort the list then find the first and last ten numbers in this list
sortList = myList
sortList.sort()
firstTen(sortList)
lastTen(sortList)
print("****************************************************************",'\n')
Language:Python 3
I don't want to give you the answer outright, so I'm going to talk you through the process and let you generate your own code.
You can't solve this problem in a single step. You need to divide repeatedly and check the value every time to see if it's odd.
Broadly speaking, when you need to repeat a process there are two ways to proceed; looping and recursion. (Ok, there are lots, but those are the most common)
When looping, you'd check if the current number x is odd. If not, halve it and check again. Once the loop has completed, x will be your result.
If using recursion, have a function that takes x. If it's odd, simply return x, otherwise call the function again, passing in x/2.
Either of those methods will solve your problem and both are fundamental concepts.
adding to what #Basic said, never do import * is a bad practice and is a potential source of problem later on...
looks like you are still confuse in this simple matter, you want to given a number X reduce it to a odd number by dividing it by 2, right? then ask yourself how I do this by hand? the answer is what #Basic said you first ask "X is a even number?" if the answer is No then I and done reducing this number, but if the answer is Yes then the next step dividing it by 2 and save the result in X, then repeat this process until you get to the desire result. Hint: use a while
to answer your question about
for num in myList:
if num != 0:
num = float(num)
num / 2
the problem here is that you don't save the result of the division, to do that is as simple as this
for num in myList:
if num != 0:
num = float(num)
num = num / 2