Please bear with me, I have been using Python for only 2 weeks.
I am writing a small project which includes using a user defined key to scramble a text file (string).
Example:
String = "Monty"
Key = 1232
The first thing I do is split it into letters so they become:
['m','o','n','t','y'] (all letters are lowercased)
['1','2','3','2']
Easy enough so far for me.
I also have a list which has all english letters and numbers from 0-9.
Now, the scrambling part looks like this:
def encrypt0r(textList,keyList,letterList): #Encrypting the string using the key
encryptedList = []
encryptedStr = ""
for character in textList:
if character in letterList:
tempIndex = letterList.index(character) + 1 #THE 1 IS A PLACEHOLDER
encryptedList.append(letterList[tempIndex])
else:
encryptedList.append(character)
encryptedStr = "".join(encryptedList)
return encryptedStr
where the 3 lists are my list of letters, the list of 4 digits and list of all english letters and nums respectively.
The output of monty should be like so:
nqqvz
because:
index of m + 1 = n
index of o + 2 = q
index of n + 3 = q
index of t + 2 = v
index of y + 1 = z **Note how when the keyList is already over, it goes back to the start of the keyList. How can I make it go through the list then once it does so once, go through it again.
If there is a faster way with the steps, I would love to hear it. I keep getting these godsent images of [0::4] - [3::4] in my head but I have no idea how to implement it.
My second problem is similar to my first:
The placeholder in the above code is just to check if my program actually works without the user defined key. And it does, unless you tell it to go past the letterlist. The list ends at [......,'8','9'], so 8 + 1 will be scrambled as 9 but I want 9 + 1 to go BACK to the start of this same list back and scramble the 9 as an "a". I've been scouring the internet for 2 days and i finally caved in to posting here.
Thanks in advance for your help. Just asking you guys to keep the jargon/lingo a little more understandable to whats essentially a script kiddie (me), and if you have a solution, explain to me how it works so that I may learn and use it in a future project!
Part 1
Every letter in the input is coupled to an element in the key list. This means this is a job for zip (izip in python 2):
for character, key in zip(textList, keyList):
# processing
The problem is that if keyList is shorter than textList, it will stop at the end of keyList. However, there is a nice tool in itertools just for this: itertools.cycle:
for character, key in zip(textList, itertools.cycle(keyList)):
# processing
Part 2
If the index to get is greater than the length of the letterList, you want to start again from the front. This means the index to get is the modulo of the index and the length of the list:
encryptedList.append(letterList[tempIndex % len(letterList)])
Looking up an index has worst case complexity O(n), meaning it will look at every element in the list, if the wanted element is at the end. To make these lookups a lot faster, build a dictionary of the keys before you start and look up the indices in that (O(1) complexity):
lettermap = {letter: i for i, letter in enumerate(letterList)}
And then in your loop:
if character in lettermap:
tempIndex = lettermap[character]
All together
def encrypt0r(text, keys, letters):
encrypted = []
lettermap = {letter: i for i, letter in enumerate(letters)}
for character, key in zip(text, itertools.cycle(keys)):
if character in lettermap:
new_index = lettermap[character] + key
encrypted.append(letters[new_index%len(letters)])
else:
encrypted.append(character)
return "".join(encrypted)
Related
this is what I tried but it output different strings
import string
import random
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
return ''.join(random.choice("abcdefghijklmnopqrstuvwxyz") for _ in range(5))
print(id_generator())
For your particular example, you can use itertools.product:
from string import ascii_lowercase
from itertools import product
list(map(''.join, product(ascii_lowercase, [ascii_lowercase[1:]])))
Output:
['abcdefghijklmnopqrstuvwxyz',
'bbcdefghijklmnopqrstuvwxyz',
'cbcdefghijklmnopqrstuvwxyz',
'dbcdefghijklmnopqrstuvwxyz',
'ebcdefghijklmnopqrstuvwxyz',
'fbcdefghijklmnopqrstuvwxyz',
'gbcdefghijklmnopqrstuvwxyz',
'hbcdefghijklmnopqrstuvwxyz',
'ibcdefghijklmnopqrstuvwxyz',
'jbcdefghijklmnopqrstuvwxyz',
'kbcdefghijklmnopqrstuvwxyz',
'lbcdefghijklmnopqrstuvwxyz',
'mbcdefghijklmnopqrstuvwxyz',
'nbcdefghijklmnopqrstuvwxyz',
'obcdefghijklmnopqrstuvwxyz',
'pbcdefghijklmnopqrstuvwxyz',
'qbcdefghijklmnopqrstuvwxyz',
'rbcdefghijklmnopqrstuvwxyz',
'sbcdefghijklmnopqrstuvwxyz',
'tbcdefghijklmnopqrstuvwxyz',
'ubcdefghijklmnopqrstuvwxyz',
'vbcdefghijklmnopqrstuvwxyz',
'wbcdefghijklmnopqrstuvwxyz',
'xbcdefghijklmnopqrstuvwxyz',
'ybcdefghijklmnopqrstuvwxyz',
'zbcdefghijklmnopqrstuvwxyz']
For this problem randomizing things doesn't sound a good idea.
Because
Random can reproduce already existing ID.
You need to keep track of already given IDs to make sure you didn't regenerate the same ID.
We should take a look to real example of this kind of problems. Real examples has rules to make sure
An ID is real with small effort.
Make easy to generate.
I am living in Turkey and Turkish ID numbers has some (those of I am aware of) rules:
All numbers should be 11 digits.
All ID numbers must be even. End with an even digit.
The last digit must be equal to the reminder of first 10 digits divided by 10.
In the university that I work, every student is given a number. The rule:
The first 2 digits of this number is the year that the student joined the university. (21 for 2021)
Next 3 number is the identifier of the faculty/institute that student is a member of.
3 number is the department
The reminding numbers are the order that the student is accepted to the department.
Now coming to your question. The image you showed is just the permutation of a given list (alphabet).
For this you should understand the number of permutation grows fast. n!/(n-r)!
where n is number of elements (in your example the alphabet) and r is the length of string (in your example the ID).
Here Python's generators come to rescue.
We need a function to generate permutation. And if it give a state, it should start from there:
def nex_permutation(list_of_elements, r, start_from):
res = ""
if len(start_from) != r:
raise ValueError(f"start_from length and r are not equal")
carry = 1
for i in start_from[::-1]:
ind = list_of_elements.index(i) + carry
carry = ind // len(list_of_elements)
res += list_of_elements[ind % len(list_of_elements)]
return res[::-1]
Notice: with this code
We did not check if the given start_from contains only elements from list_of_elements
We going to the first permutation if we try to continue from last possible permutation.
I leave these problems to you.
Now we can have a function using nex_permutation to generate next one. Here We will use yield instead of return. Thus this function become a generator. And with generators you can calculate the next element as long as you want.
def permuataion(list_of_elements, r, start_from=None):
if start_from is None:
start_from = list_of_elements[0] * r
yield start_from
while True:
start_from = nex_permutation(list_of_elements, r, start_from=start_from)
yield start_from
Now let's to use it:
a = permuataion("abcd", 4)
for _ in range(3):
print(next(a))
output:
aaaa
aaab
aaac
Test if it continues:
a = permuataion("abcd", 4, start_from="aabd")
for _ in range(3):
print(next(a))
output:
aaca
aacb
aacc
This seems like a homework assignment, so I'll give you some pseudocode to work with.
# Create a list of all the ascii lowercase characters.
# Get a random letter from list of ascii lowercase letters.
# Make sure it isn't the first letter.
# Replace the first letter in the list of all ascii lowercase letters
# with the random letter.
# Create a str from the list of all the ascii lowercase letters
There is a problem where array containing numbers is given, the statement is to find the maximum length of a sub-sequence formed from the given array such that all the elements in that sub-sequence share at least one common digit.
Now whats the catch? Well, I intended to use a dictionary b to store key as every digit and value as count so far while traversing the given array, digit by digit. I thought the maximum number in values of dictionary i.e., bigger count of a digit would be the problems answer, given that we still have a glitch that we should not count a same digit that present in ONE element of array more than one time. To overcome that glitch, I used set c.
The code function for this along with driver function written below for convinience.
def solve (a):
b={}
answer=1
for i in a:
j=i
c=set()
c.clear()
while(j):
last_digit=i%10
if(last_digit not in b and last_digit not in c):
b[last_digit]=1
c.add(last_digit)
elif(last_digit in b and last_digit not in c):
b[last_digit]+=1
c.add(last_digit)
answer=max(answer,b[last_digit])
j//=10
return answer
a=list(map(int,input().strip().split()))
print(solve(a))
There are lot test cases concerned for this code to be correct.. One of them is input is 12 11 3 4 5, the output that code gave is 1 and expected output is 2. What gives?
You have good ideas. But your code would be easier if you use the Counter object from the collections module. It is designed to do just what you are trying to do: count the number of occurrences of an item in an iterable.
This code uses a generator expression to look at each value in the list alist, uses the built-in str() function to convert that integer to a string of digits, then uses the set() built-in function to convert that to a set. As you said, this removes the duplicate digits since you want to count each digit only once per item. The Counter object then looks at these digits and counts their occurrences. The code then uses Counter's most_common method to choose the digit that occurs most (the (1) parameter returns only the single most popular digit in a list, and the 0 index takes that digit and its count out of the list) then takes the count of that digit (that's the 1 index). That count is then returned to the caller.
If you are not familiar with Counter or with generator expressions, you could do the counting yourself and use regular for loops. But this code is short and fairly clear to anyone who knows the Counter object. You could use the line in the comment to replace the following four lines, if you want brief code, but I expanded out the code to make it more clear.
from collections import Counter
def solve(alist):
digitscount = Counter(digit for val in alist for digit in set(str(abs(val))))
# return digitscount.most_common(1)[0][1]
most_common_list = digitscount.most_common(1)
most_common_item = most_common_list[0]
most_common_count = most_common_item[1]
return most_common_count
alist = list(map(int, input().strip().split()))
print(solve(alist))
For your example input 12 11 3 4 5, this prints the correct answer 2. Note that my code will give an error if the input is empty or contains a non-integer. This version of my code takes the absolute value of the list values, which prevents a minus (or negative) sign from being counted as a digit.
Here's my own implementation of this:
def solve(list_of_numbers):
counts = {str(i):0 for i in range(10)} # make a dict of placeholders 0 through 9
longest_sequence = 0 # store the length of the longest sequence so far
for num in list_of_numbers: # iterate through our list of numbers
num_str = str(num) # convert number to a string (this makes "is digit present?" easier)
for digit, ct in counts.items(): # evaluate whether each digit is present
if digit in num_str: # if the digit is present in this number...
counts[digit] += 1 # ...then increment the running count of this digit
else: # otherwise, we've broken the sequence...
counts[digit] = 0 # ...so we reset the running count to 0.
if ct > longest_sequence: # check if we've found a new longest sequence...
longest_sequence = ct # ...and if so, replace the current longest sequence
return longest_sequence[1] # finally, return the digit that had the longest running sequence.
It uses a dict to store the running counts of each digit's consecutive occurrences - for every number, the count is incremented if the digit is present, and reset to 0 if it isn't. The longest sequence's length so far is saved in its own variable for storage.
There are a few details that your implementation, I think, is overlooking:
Your code might be returning the digit that appears the most, rather than the greatest number of appearances. I'm not sure, because your code is kind of hard for me to parse, and you only gave the one test example.
Try to stay away from using single-letter variable names, if you can. Notice how much more clear my code above is, since I've used full names (and, at worst, clear abbreviations like ct for "count"). This makes it much easier to debug your own code.
I see what you're doing to find the digits that are present in the number, but that's a bit more verbose than the situation requires. A simpler solution, which I used, was to simply cast the number into a string and use each individual digit's character instead of its value. In your implementation, you could do something like this: c = set(int(digit) for digit in str(j))
You don't seem to have anything in your code that detects when a digit is no longer present, which could lead to an incorrect result.
I'm having trouble understanding the original problem, but I think what you need to do is cast each item as a string if it is an int and then split out each digit.
digits = {}
for item in thelist:
digit[item] = []
if len(item) > 1:
for digit in str(item):
digits[item].append(int(digit))
if your test case is 12 11 3 4 5 then this would produce a dictionary of {12 : [1,2], 11 : [1,1], etc}
Python beginner here, sorry if this is a dumb question.
So I have a long string, and I need to add a character in very specific areas of the strings. For example, a | after character number 23, 912, and 1200. I read this Add string in a certain position in Python, but it only works for adding one character.
Also, the solution needs to be expandable, not just do it 3 times. The code I'm making can have lots of different locations with where I want the character to be.
With reference to the link that you posted Add string in a certain position in Python;
If you would like to repeat the operation for different values, you could create a list containing all index positions where you would like your | character to be inserted.
For example,
>>> l = [1, 3, 4]
>>> s = "abcdef"
>>> for i in l:
>>> s = s[:i] + "|" + s[i:] # as suggested in your link
>>> s
'a|b||cdef'
This will allow you to repeat the process for the set of values that you provide in the list. You could also define a function to assist in this, which I could explain if this method is insufficient!
Note, however, that this will insert the character relative to the current iteration. That is, in this example, after adding the | at position 1, the next insert position, 3, is different from what it was before the first insert. You could avoid this (if you want) by including a counter variable to offset all the index positions by the number of inserts that have been executed (will require initial list to be ordered).
Not so good at python, hope I can help
According to that site you went to, you can make a while loop to solve the problem
The code should look something like this
def insert_dash(string, index, addin):
return string[:index] + addin + string[index:]
alldone = False
string = input("String: ")
index = " "
while index:
index = input("Index: ")
addin = input("Add into: ")
string = insert_dash(string, index, addin)
Hope it helps!
PS: I have NOT tried the code, but I think it will work
firstsentence = input('Enter a sentence: ')
firstsentence = firstsentence.lower()
words = firstsentence.split(' ')
my_list = []
my_list.append(words)
for (i, firstsentence) in enumerate(my_list):
if (aword == my_list): #This is where i get confused
print(str(i+1)+ ' position')
print (my_list)
So what i am try to do is ask the user for an input - "firstsentence". I will then try to split the inputted sentence into words and store them in the array (list) my_list. I am getting stuck on how to convert the seperated words into numbers (their positions in the sentence) and then printing out the input("firstsentence") as the integer version. 'aword' is what i used to try and identify if the word was repeated in the sentence. This is quite confusing and here is an example :-
"I like to do coding because I like it and i like it a lot"
There are 15 words here. Of these 15, only 10 are different. So the repeated words MUST be put into the same integer (even though their positions are different their actual word is the same) value in the array. The code i want to print out should look like this for the sentence above:-
1 2 3 4 5 6 1 2 7 8 1 2 7 9 10. I am really confused as to how to store the separated words as different values (integers) and then especially on how to store the same repeating words as one value, and then printing the whole thing out. Thanks to those who help. Would be much appreciated :-).
My answer is deliberately incomplete. It's clear you're new at this, and part of being new is discovering how code works. But you're lacking in some basic concepts of what to do with lists in python, and this should point you in the right direction.
firstsentence = input('Enter a sentence: ')
firstsentence = firstsentence.lower()
words = firstsentence.split(' ')
my_list = []
for word in words:
print(word in my_list)
# You can do something more useful than print here, right?
# Maybe add the specific word to my_list...
for word in words:
print(my_list.index(word))
# This gives you the index, but you need to figure out how to output it the way you want
# Note that indices in python start at 0 while your sample output starts
# at 1. So maybe do some addition somewhere in here.
So, what's happening here?
We're doing two passes.
Generally, you'll get very far in programming if you can decompose a problem into discrete steps. In this case, there are two steps to your problem - find the index of the first occurrence of each word, and then output the right indices.
In the first pass, you'll create a list of unique words, where their ordering reflects their ordering in the sentence.
In the second pass, you'll go through the original sentence and look up the place where it first occurred, and format that the way you need.
If you're really attentive, you'll realize: you could easily do this in one pass. What does the second pass require? Just that the word you're looking for be in my_list. As long as you meet that requirement, you could combine the two loops. This is a good thing to do - it may not matter when you're looking at 20 words, but what if you were looking at 20,000,000,000 words? You'd really only want one loop. But take small steps. Start by figuring out how to do it with two loops, and then maybe move on to putting it all in one.
This question already has answers here:
How to find all occurrences of a substring?
(32 answers)
Closed 6 years ago.
As you can see the program will ask the user for two string, it should ask for the longer string first then it needs to check the entire longer string for instances of the shorter string. If i find one, print out the index the match started at. and the program does this until it checked the entire longer string. I am new to python and I got stuck, if there are any suggestions please put it at a novice level so I understand without jumping into any advance techniques. This program should be cap sensitive as well.
I am trying to find the shorter stringer and index it as many times as it appears (see projected output), by using slicing, indexing, and using a loop.
def main():
longer = [input("First (longer) string: ")]
shorter = input("Second (shorter) string: ")
for shorter in longer:
print("at index ","found a slice of ", shorter)
main
my projected output should be something like this:
longer: she sells seashells by the seashore.
shorter: sea
at index 10 found a slice of sea
at index 27 found a slice of sea
Well, to get the first occurrence of the shorter string in the longer, you could use:
longer.find(shorter)
As requested in the comment below, you can write your own find method:
def find_str(s, char):
index = 0
if char in s:
c = char[0]
for ch in s:
if ch == c:
if s[index:index+len(char)] == char:
return index
index += 1
return -1
print(find_str("she sells seashells by the seashore", "sea"))
Please try this :
a = 'she sells seashells by the seashore'
b = 'sea'
for v in [ i.start() for i in re.finditer(r'' + b + '',a) ]:
print "at index {0} found a slice {1}".format(v,b)