Keeping track of skipped numbers in Python - python

I'm pretty new to Python and I'm looking for a way for Python to keep track of skipped numbers in a sequence. For example, if I have a folder with pictures numbered 1-100, but 47, 58 and 98 are missing in the directory, how can I keep track of this?

You can subtract your set with missing numbers from a complete set of all the numbers, e.g.:
>>> incomplete_set = { 0, 1, 2, 3, 4, 6, 8, 9 }
>>> complete_set = set(range(10))
>>> complete_set - incomplete_set
set([5, 7])

Related

Returning a list of the ordered elements with a conition in while loop structure

I am trying to solve a assignment where are 13 lights and starting from 1, light is turned off at every 5th light, when the count reaches 13, start from 1st item again. The function should return the order of lights turned off. In this case, for a list of 13 items, the return list would be [5, 10, 2, 8, 1, 9, 4, 13, 12, 3, 7, 11, 6]. Also, turned off lights would not count again.
So the way I was going to approach this problem was to have a list named turnedon, which is [1,2,3,4,5,6,7,8,9,10,11,12,13] and an empty list called orderoff and append to this list whenever a light gets turned off in the turnedon list. So while the turnedon is not empty, iterate through the turnedon list and append the light getting turned off and remove that turnedoff light from the turnedon list, if that makes sense. I cannot figure out what should go into the while loop though. Any idea would be really appreciated.
def orderoff():
n=13
turnedon=[]
for n in range(1,n+1):
turnedon.append(n)
orderoff=[]
while turneon !=[]:
This problem is equivalent to the well-known Josephus problem, in which n prisoners stand in a circle, and they are killed in a sequence where each time, the next person to be killed is k steps around the circle from the previous person; the steps are only counted over the remaining prisoners. A sample solution in Python can be found on the Rosetta code website, which I've adapted slightly below:
def josephus(n, k):
p = list(range(1, n+1))
i = 0
seq = []
while p:
i = (i+k-1) % len(p)
seq.append(p.pop(i))
return seq
Example:
>>> josephus(13, 5)
[5, 10, 2, 8, 1, 9, 4, 13, 12, 3, 7, 11, 6]
This works, but the results are different from yours:
>>> pos = 0
>>> result = []
>>> while len(result) < 13 :
... pos += 5
... pos %= 13
... if pos not in result :
... result.append(pos)
...
>>> result = [i+1 for i in result] # make it 1-based, not 0-based
>>> result
[6, 11, 3, 8, 13, 5, 10, 2, 7, 12, 4, 9, 1]
>>>
I think a more optimal solution would be to use a loop, add the displacement each time, and use modules to keep the number in range
def orderoff(lights_num,step):
turnd_off=[]
num =0
for i in range(max):
num =((num+step-1)%lights_num)+1
turnd_off.append(num)
return turnd_off
print(orderoff(13))

Python - Counter merges elements from list together

I have a list full of Windows API calls:
listOfSequences =
['GetSystemDirectoryA',
'IsDBCSLeadByte',
'LocalAlloc',
'CreateSemaphoreW',
'CreateSemaphoreA',
'GlobalAddAtomW',
'lstrcpynW',
'LoadLibraryExW',
'SearchPathW',
'CreateFileW',
'CreateFileMappingW',
'MapViewOfFileEx',
'GetSystemMetrics',
'RegisterClipboardFormatW',
'SystemParametersInfoW',
'GetDC',
'GetDeviceCaps',
'ReleaseDC', ...... and so on .....]
Since some of them occurs several times, I wanted to collected their number of occurences. Thus, I used collections.Counter.
But it concatenates some APIs together:
lCountedAPIs = Counter(listOfSequences)
when I print the lCountedAPIs I get the folowing:
Counter({'IsRectEmptyLocalAlloc': 2,
'DdePostAdvise': 3,
'DispatchMessageWGetModuleFileNameA': 2,
'FindResourceExW': 50318,
'ReleaseDCGetModuleFileNameW': 7,
'DefWindowProcAGetThreadLocale': 1,
'CoGetCallContext': 40,
'CoGetTreatAsClassGetCommandLineA': 1,
'GetForegroundWindowGetSystemDirectoryW': 1,
'GetModuleHandleWGetSystemTimeAsFileTime': 2,
'WaitForSingleObjectExIsChild': 1,
'LoadIconAGetWindowsDirectoryW': 2,
'GlobalFreeLocalAlloc': 10,
'GetMapModeCreateSemaphoreW': 1,
'HeapLock': 11494, <---------- A
'CharNextAGetCurrentProcessId': 11, <---------- B
'RemovePropWGetStartupInfoA': 1,
'GetTickCountGetVersionExW': 55,
So for ex.:
HeapLock (see A) was not merged with another API
But CharNextA was concatenated with GetCurrentProcessId (see B)
Can somebody tell me why this happens and how to fix that ?
Thanks in advcance & best regards :)
Check your list definition. Python concatenates adjacent string literals, so you must have missed a comma somewhere in the the middle:
listOfSequences = [
'GetSystemDirectoryA',
'IsDBCSLeadByte',
'LocalAlloc',
...
'CharNextA'
# ^ comma missing here
'GetCurrentProcessId',
...
]
This has bitten me several times.
Nothing in Counter does that. You must necessarily have 11 occurrences of 'CharNextAGetCurrentProcessId' in listOfSequences. You can check this by running 'CharNextAGetCurrentProcessId' in listOfSequences.

Handling lists in Python

Suppose I have a list:
a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
I want to write a program that prints out all the elements of the list that are less than 10.
Actually its pretty simple I got this program but, I need to do it in a single line and I've no idea how to do that. Need some help with this.
print [x for x in a if x < 10]
Take a further look at lambda functions, I feel this is what you are looking for.
So in order to print something out of a list that is less than 10 In the same line, first you need to create a list:
numbers = []
loop through every single element of the list
for i in a:
And then you need a If statement to check if the element is less than 10
if i < 10:
Append the number to the list
numbers.append(str(i))
Join the results together:
result = " ".join(numbers)
And lastly printing it out
print(result)
And if you combine everything together, this is what you should get:
a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
numbers = []
for i in a:
if i < 10:
numbers.append(str(i))
result = " ".join(numbers)
print(result)
The result should be:
1 1 2 3 5 8

Using combinatorics in Python to list 4-digit passcodes

I came across this interesting article about why using 3 unique numbers for a 4-digit passcode is the most secure: (LINK)
The math involved is pretty straightforward - if you have to guess a phone's 4-digit passcode based on the smudges left on the screen, then:
4 smudges indicates that there are 4 unique numbers in the passcode. Since each of them must be used at least once, then we have 4! = 24 possible passcodes.
With 3 distinct numbers, the passcode becomes a little more secure. Since there are three smudges, one number is repeated - but we don't know which one. So accounting for multiplicity, we get (4!/2!) x 3 = 36 possible passcodes.
Similarly, with 2 distinct numbers, we get 14 possible passcodes.
My question is, is there any way I can "prove" the above in Python? A way to justify that 3 numbers gives the most secure passcode, with Python code, probably something that lists out all possible passcodes if you give it some numbers? I was thinking about using itertools, with itertools.permutations as a starting point, but then I found that Python has a combinatorics module, which may be a far more elegant way. Would someone be kind enough to show me how to use it? I'm reading the documentation right now but some syntax is escaping me.
There is no combinatorics module in the standard distribution, but this is easy to do regardless. For example,
def guess(smudged_numbers):
from itertools import product
num_smudges = len(smudged_numbers)
for raw in product(smudged_numbers, repeat=4):
if len(set(raw)) == num_smudges:
yield raw
count = 0
for nums in guess([1, 8]):
print nums
count += 1
print "total", count
That prints:
(1, 1, 1, 8)
(1, 1, 8, 1)
(1, 1, 8, 8)
(1, 8, 1, 1)
(1, 8, 1, 8)
(1, 8, 8, 1)
(1, 8, 8, 8)
(8, 1, 1, 1)
(8, 1, 1, 8)
(8, 1, 8, 1)
(8, 1, 8, 8)
(8, 8, 1, 1)
(8, 8, 1, 8)
(8, 8, 8, 1)
total 14
The search space is very small (len(num_smudges)**4, which as at most 4**4 = 256), so no point to doing anything fancier ;-)
How it works: it generates all possible (product) 4-tuples (repeat=4) containing the passed-in sequence of smudged numbers. So for [1, 8], it generates all 2**4 = len(smudged_numbers)**4 = 16 possibilities for a 4-tuple containing nothing but 1's and 8's.
Converting a raw possibility to a set then tells us how many (len) different numbers appear in the raw 4-tuple. We only want those containing all the smudged numbers. That's all there is to it. In the [1, 8] case, this step only weeds out 2 of the 16 raw 4-tuples: (1, 1, 1, 1) and (8, 8, 8, 8).
My try with the permutations method in the itertools module.
I have added the shuffle method from the random module to generate more random tries from normal crackers. (To try your luck you would never go serially would you?!) But, if you want the serial tries method, you can just remove the shuffle(codes_to_try) line.
from itertools import combinations, permutations
from random import randint, shuffle
def crack_the_code(smudges, actual_code):
""" Takes a list of digit strings (smudges) & generates all possible
permutations of it (4 digits long). It then compares the actual given
code & returns the index of it in the generated list, which basically
becomes the number of tries.
"""
attempts_to_crack = 0
no_smudges = len(smudges)
if no_smudges == 3:
all_codes = ["".join(digits)
for repeated_num in smudges
for digits in permutations([repeated_num]+smudges)
]
all_codes = list(set(all_codes)) # remove duplicates
elif no_smudges == 4:
all_codes = ["".join(digits)
for digits in permutations(smudges)
]
else:
print "Smudges aren't 3 or 4"
raise ValueError
shuffle(all_codes)
return all_codes.index(actual_code)
print crack_the_code(["1","2","3"],"1232")
# above prints random values between 0 & 35 inclusive.
Note - You may play around with the function if you like int & not str.
PS - I have kept the code self-explanatory, but you can always comment & ask something you don't understand.

Merge python lists in a specific order/sequence

I'm trying to make two lists of the sort:
list_numbers = [1,2,3,4,5,6,7,8,9,10,11,12]
list_letters= ["onetothree", "fourtosix", "seventonine", "tentotwelve"]
into
list_both= ["onetothree",1,2,3,"fourtosix",4,5,6...]
This is just a way to describe my problem. I need to do this with all the elements in list_numbers & list_letters. The number or elements in list_numbers will always be dividable by the amount of elements in list_letters so theres no need to worry about "crooked data".
After searching for a good three hours, trying with many different kinds of "for" and "while" loops and only getting python 2.x questions, bad results and syntax errors, I thought I'd maybe deserve to post this question.
Hacky, but it'll get the job done
>>> list_numbers = [1,2,3,4,5,6,7,8,9,10,11,12]
>>> list_letters= ["onetothree", "fourtosix", "seventonine", "tentotwelve"]
>>> list(itertools.chain.from_iterable(zip(list_letters, *zip(*[list_numbers[i:i+3] for i in range(0, len(list_numbers), 3)]))))
['onetothree', 1, 2, 3, 'fourtosix', 4, 5, 6, 'seventonine', 7, 8, 9, 'tentotwelve', 10, 11, 12]
Or, the cleaner version:
>>> answer = []
>>> i = 0
>>> for letter in list_letters:
... answer.append(letter)
... for j in range(3):
... answer.append(list_numbers[i+j])
... i += j+1
...
>>> answer
['onetothree', 1, 2, 3, 'fourtosix', 4, 5, 6, 'seventonine', 7, 8, 9, 'tentotwelve', 10, 11, 12]
Of course, if you don't have sufficiently many entries in list_numbers, you this will burn you
try this:
list_numbers = [1,2,3,4,5,6,7,8,9,10,11,12]
list_letters= ["onetothree", "fourtosix", "seventonine", "tentotwelve"]
list_both=[]
c=1
for n in range(len(list_letters)):
list_both.append(list_letters[n])
list_both[c+n:c+n]=list_numbers[c-1:c+2]
c+=3
print(list_both)

Categories

Resources