Python itertools product start from certain - python-3.x

I have a very big product expected from a itertools.product.
for result in product(items, repeat=9):
# stuff
It takes a lot of time, and I am searching for a way to start from a certain item because I won't be able to do it on one run.
I could do the following:
gen = product(items, repeat=9):
for temp in gen:
if temp == DESIRED_VALUE:
break
for result in gen:
# stuff
But it will take a lot of time, almost the same as if I was just restarting the program. So, is there a way to "skip ahead" without wasting the time on iterating the whole thing?

Although I have serious concerns about brute-forcing a passsword in the first place, I can offer an answer.
You can use islice to skip a certain number of steps in iteration. This means that you would need to keep track of how many attempts you have done so far to know where to resume later.
START_VALUE = 200
all_combos = itertools.product(letters,repeat=9)
#start at START_VALUE and stop at None (the end)
combos = itertools.islice(all_combos,START_VALUE,None)
for i,password in enumerate(combos,start=START_VALUE):
...
note that this will only work for values below sys.maxsize.
You can also calculate the index of a given password with the same formula to convert bases:
def check_value(password):
pos = len(letters)
value = 0
for i,c in enumerate(reversed(password)):
value+= (pos**i) * letters.index(c)
return value
>>> check_value("aaaacbdaa")
29802532

Related

Defining a function to find the unique palindromes in a given string

I'm kinda new to python.I'm trying to define a function when asked would give an output of only unique words which are palindromes in a string.
I used casefold() to make it case-insensitive and set() to print only uniques.
Here's my code:
def uniquePalindromes(string):
x=string.split()
for i in x:
k=[]
rev= ''.join(reversed(i))
if i.casefold() == rev.casefold():
k.append(i.casefold())
print(set(k))
else:
return
I've tried to run this line
print( uniquePalindromes('Hanah asked Sarah but Sarah refused') )
The expected output should be ['hanah','sarah'] but its returning only {'hanah'} as the output. Please help.
Your logic is sound, and your function is mostly doing what you want it to. Part of the issue is how you're returning things - all you're doing is printing the set of each individual word. For example, when I take your existing code and do this:
>>> print(uniquePalindromes('Hannah Hannah Alomomola Girafarig Yes Nah, Chansey Goldeen Need log'))
{'hannah'}
{'alomomola'}
{'girafarig'}
None
hannah, alomomola, and girafarig are the palindromes I would expect to see, but they're not given in the format I expect. For one, they're being printed, instead of returned, and for two, that's happening one-by-one.
And the function is returning None, and you're trying to print that. This is not what we want.
Here's a fixed version of your function:
def uniquePalindromes(string):
x=string.split()
k = [] # note how we put it *outside* the loop, so it persists across each iteration without being reset
for i in x:
rev= ''.join(reversed(i))
if i.casefold() == rev.casefold():
k.append(i.casefold())
# the print statement isn't what we want
# no need for an else statement - the loop will continue anyway
# now, once all elements have been visited, return the set of unique elements from k
return set(k)
now it returns roughly what you'd expect - a single set with multiple words, instead of printing multiple sets with one word each. Then, we can print that set.
>>> print(uniquePalindromes("Hannah asked Sarah but Sarah refused"))
{'hannah'}
>>> print(uniquePalindromes("Hannah and her friend Anna caught a Girafarig and named it hannaH"))
{'anna', 'hannah', 'girafarig', 'a'}
they are not gonna like me on here if I give you some tips. But try to divide the amount of characters (that aren't whitespace) into 2. If the amount on each side is not equivalent then you must be dealing with an odd amount of letters. That means that you should be able to traverse the palindrome going downwards from the middle and upwards from the middle, comparing those letters together and using the middle point as a "jump off" point. Hope this helps

How to process the data returned from a function (Python 3.7)

Background:
My question should be relatively easy, however I am not able to figure it out.
I have written a function regarding queueing theory and it will be used for ambulance service planning. For example, how many calls for service can I expect in a given time frame.
The function takes two parameters; a starting value of the number of ambulances in my system starting at 0 and ending at 100 ambulances. This will show the probability of zero calls for service, one call for service, three calls for service….up to 100 calls for service. Second parameter is an arrival rate number which is the past historical arrival rate in my system.
The function runs and prints out the result to my screen. I have checked the math and it appears to be correct.
This is Python 3.7 with the Anaconda distribution.
My question is this:
I would like to process this data even further but I don’t know how to capture it and do more math. For example, I would like to take this list and accumulate the probability values. With an arrival rate of five, there is a cumulative probability of 61.56% of at least five calls for service, etc.
A second example of how I would like to process this data is to format it as percentages and write out a text file
A third example would be to process the cumulative probabilities and exclude any values higher than the 99% cumulative value (because these vanish into extremely small numbers).
A fourth example would be to create a bar chart showing the probability of n calls for service.
These are some of the things I want to do with the queueing theory calculations. And there are a lot more. I am planning on writing a larger application. But I am stuck at this point. The function writes an output into my Python 3.7 console. How do I “capture” that output as an object or something and perform other processing on the data?
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import math
import csv
def probability_x(start_value = 0, arrival_rate = 0):
probability_arrivals = []
while start_value <= 100:
probability_arrivals = [start_value, math.pow(arrival_rate, start_value) * math.pow(math.e, -arrival_rate) / math.factorial(start_value)]
print(probability_arrivals)
start_value = start_value + 1
return probability_arrivals
#probability_x(arrival_rate = 5, x = 5)
#The code written above prints to the console, but my goal is to take the returned values and make other calculations.
#How do I 'capture' this data for further processing is where I need help (for example, bar plots, cumulative frequency, etc )
#failure. TypeError: writerows() argument must be iterable.
with open('ExpectedProbability.csv', 'w') as writeFile:
writer = csv.writer(writeFile)
for value in probability_x(arrival_rate = 5):
writer.writerows(value)
writeFile.close()
#Failure. Why does it return 2. Yes there are two columns but I was expecting 101 as the length because that is the end of my loop.
print(len(probability_x(arrival_rate = 5)))
The problem is, when you write
probability_arrivals = [start_value, math.pow(arrival_rate, start_value) * math.pow(math.e, -arrival_rate) / math.factorial(start_value)]
You're overwriting the previous contents of probability_arrivals. Everything that it held previously is lost.
Instead of using = to reassign probability_arrivals, you want to append another entry to the list:
probability_arrivals.append([start_value, math.pow(arrival_rate, start_value) * math.pow(math.e, -arrival_rate) / math.factorial(start_value)])
I'll also note, your while loop can be improved. You're basically just looping over start_value until it reaches a certain value. A for loop would be more appropriate here:
for s in range(start_value, 101): # The end value is exclusive, so it's 101 not 100
probability_arrivals = [s, math.pow(arrival_rate, s) * math.pow(math.e, -arrival_rate) / math.factorial(s)]
print(probability_arrivals)
Now you don't need to manually worry about incrementing the counter.

Is there a save way to retrieve the index of a list without try catch?

I would like to know if there is a save and fast way of retrieving the index of an element in a list in python 3.
Idea:
# how I do it
try:
test_index = [1,2,3].index(4) # error
except:
# handle error
# how I would like to do it:
test_index = [1,2,3].awesome_index(4) # test_index = -1
if test_index == -1:
# handle error
The reason, why I would like to not use try, except is because try-except appears to be a little bit slower that an if-statement. Since I am handling a lot of data, performance is important to me.
Yes, I know that I could implement awesome_index by simply looping through the list, but I assume that there already is a function doing exactly that in a very efficient way.
There is no such thing, but I like your thinking, so let's built upon it:
If you have only one index, and create many queries against it, why not maintain a set() or a dict() right next to that index?
numbers = [1,2,3]
unique_nunbers = set(numbers)
if 4 in unique_nunbers:
return numbers.index(4)
Dict option:
numbers = [1,2,3]
unique_nunbers = dict(zip(numbers, range(len(numbers))))
index = unique_nunbers.get(4)
if index is None:
# Do stuff
Lookups inside sets and dicts O(1), thus 4 in unique_numbers costs almost nothing. Iterating over the whole list in case something doesn't exist though, is a wasted O(n) operation.
This way, you have a way more efficient code, with a better algorithm, and no excepctions!
Keep in mind the same thing cannot be said for 4 in numbers, as it iterates over the whole list.

Python: iterate through list and check for matching sub-string in specific parts of string

for all the strings in a list of strings, if either of the first two characters of the string match (in any order) then check if either of last two strings match in specific order. If so, I will ad an edge between two vertex in graph G.
Example:
d = ['BEBC', 'ABRC']
since the 'B' in the first two characters and the 'C' in the second two characters match, I will add an edge. I'm fairly new to Python and what I have come up with through previous searches seems overly verbose:
for i in range(0,len(d)-1):
for j in range(0,len(d)-1):
if (d[i][0] in d[j+1][:2] or d[i][1] in d[j+1][:2]) and \
(d[i][2] in d[j+1][2] or d[i][3] in d[j+1][3]):
G.add_edge(d[i],d[j+1])
The next step on this is to come up with a faster way to iterate through since there will probably only be 1 to 3 edges connecting each node, so 90% of the iteration test will come back false. Suggestions would be welcome!
Since you know that the last character of each list item needs to absolutely match in the same place it's less expensive to check for that first. The code is otherwise doing unnecessary work even though it really doesn't need to. Using timeit you can determine the difference in calculation time by making a few changes, such as checking for the last characters first:
import timeit
d = ['BEBC', 'ABRC']
def test1():
if (d[0][len(d[0])-1] is d[1][len(d[1])-1]):
for i in range(0,2):
if(d[0][i] in d[1][:2]):
return(d[0],d[1])
print(test1())
print(timeit.timeit(stmt=test1, number=1000000))
Result:
('BEBC', 'ABRC')
2.3587113980001959
Original Code:
d = ['BEBC', 'ABRC']
def test2():
for i in range(0,len(d)-1):
for j in range(0,len(d)-1):
if (d[i][0] in d[j+1][:2] or d[i][1] in d[j+1][:2]) and \
(d[i][2] in d[j+1][2] or d[i][3] in d[j+1][3]):
return(d[i],d[j+1])
print(test2())
print(timeit.timeit(stmt=test2, number=1000000))
Result:
('BEBC', 'ABRC')
3.1525327970002763
Now let's take the last list value and change it so that the last character C does not match:
d = ['BEBC', 'ABRX']
New Code:
None
0.766526217000318
Original:
None
2.963771982000253
This is where it's obviously going to pay off in regard to the order of iterating items — especially considering if 90% of the iteration checks could come back false.

Creating a function that creates two lists in Python 3

I am trying to create a function, getStocks, that gets from the user two lists, one containing the list of stock names and the second containing the list of stock prices. This should be done in a loop such that it keeps on getting a stock name and price until the user enters the string 'done' as a stock name. The function should return both lists. My main issues are figuring out what my parameters are, how to continuously take in the name and price, and what type of loop I should be using. I am very new to programming so any help would be appreciated. I believe I'm close but I am unsure where my errors are.
def getStocks(name,price):
stockNames = []
stockPrices = []
i = 0
name = str(input("What is the name of the stock?"))
price = int(input("what is the price of that stock?"))
while i < len(stockNames):
stockNames.append(name)
stockPrices.append(price)
i += 1
else:
if name = done
return stockNames
return stockPrices
Your question is a bit unclear but some things off the bat, you cant have two return lines, once you hit the first, it leaves the function. Instead you'do write something like
return (stockNames, stockPrices)
Secondly while loops dont have an else, so you'd actually set up your while loop, then setup an if statement at the beginning to check if the string is 'done', then act accordingly. Break will get you out of your last while loop, even though it looks like it's associated with the if. So something like this:
while i < len(stockNames):
if name.upper() == 'DONE':
break
else:
stockNames.append(name)
stockPrices.append(price)
i += 1
Also you have to use == (comparison) instead of = (assignment) when you check your name = done. And dont forget done is a string, so it needs to be in quotations, and I used .upper() to make the input all caps to cover if its lower case or uppercase.
If you can clear up your question a little bit, I can update this answer to include everything put together. I'm not quite understanding why you want to input a list and then also take user input, unless you're appending to that list, at which point you'd want to put the whole thing in a while loop maybe.
Update:
Based on your comment, you could do something like this and enclose the whole thing in a while loop. This takes the incoming two lists (assuming you made a master list somewhere) and sends them both into the getStocks function, where someone can keep appending to the pre-existing list, and then when they type done or DONE or DoNe (doesn't matter since you use .upper() to make the input capitalized) you break out of your while loop and return the updated lists:
def getStocks(name, price):
stockNames = name
stockPrices = price
while 1:
inputName = str(input("What is the name of the stock?"))
inputPrice = int(input("what is the price of that stock?"))
if name.upper() != 'DONE':
stockNames.append(inputName)
stockPrices.append(inputPrice)
else:
break
return (stockNames, stockPrices)
But really, depending on the rest of the structure, you might want to make a dictionary instead of having 2 separate lists, that way everything stays in key:value pairs, so instead of having to check index 0 on both and hoping they didn't get shifted by some rogue function, you'd have the key:value pair of "stock_x":48 always together.

Resources