Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 months ago.
Improve this question
How would I do this?
Write a Python program that meets the following requirements:
It prompts the user for six alphanumeric characters (A-Z, 0-9) separated by spaces.
It sorts the user input in ascending order, letters first, then numbers.
It prints the list of sorted characters to the screen (separated by spaces).
It is well commented.
Example:
If the program's input is 8 G J 4 5 D, the output would be D G J 4 5 8
I wrote a program, but when inputing data that had only numbers, it would give me an error. Any help would be appreciated.
Sort with a key so that decimal characters go before letters:
>>> s = "8 G J 4 5 D"
>>> print(*sorted(s.split(), key=lambda c: (c.isdecimal(), c)))
D G J 4 5 8
If you want your code to be almost two times faster, you can use a lookup table, I've used a one liner for this, but it can also be split up. I'm printing this to provide insight in what this object looks like. For the numbers I can make a list directly, for the letters I'll use a more compact notation.
decode = {character: index for index, character in enumerate([chr(i) for i in range(ord("A"), ord("Z") + 1)] + ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"])}
print(decode)
s = "8 G J 4 5 D"
print(*sorted(s.split(), key=lambda c: (c.isdecimal(), c)))
print(*sorted(s.split(), key = lambda c: decode[c]))
from timeit import repeat
loops = 500_000
count = 1
print(loops * min(repeat("sorted(s.split(), key=lambda c: (c.isdecimal(), c))", globals=globals(), repeat=loops, number=count)))
print(loops * min(repeat("sorted(s.split(), key = lambda c: decode[c])", globals=globals(), repeat=loops, number=count)))
Output:
{'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6, 'H': 7, 'I': 8, 'J': 9, 'K': 10, 'L': 11, 'M': 12, 'N': 13, 'O': 14, 'P': 15, 'Q': 16, 'R': 17, 'S': 18, 'T': 19, 'U': 20, 'V': 21, 'W': 22, 'X': 23, 'Y': 24, 'Z': 25, '0': 26, '1': 27, '2': 28, '3': 29, '4': 30, '5': 31, '6': 32, '7': 33, '8': 34, '9': 35}
D G J 4 5 8
D G J 4 5 8
3.6460114642977715
2.3174798116087914
More ideas?
# NOTE: This code is definitely not the most efficient.
import re # Import the regex standard library to check the input later
input_ = input("Enter six alphanumeric characters, separated by spaces: ") # Get the input
# Check if the input is six alphanumeric characters, separated by spaces.
# [A-Z0-9] in regex matches any character in the A-Z (capitalized) or 0-9 range
# ^ in regex matches the BEGINNING of the string
# $ in regex matches the END of the string
if not re.match(r"^[A-Z0-9] [A-Z0-9] [A-Z0-9] [A-Z0-9] [A-Z0-9] [A-Z0-9]$", input_): # If the string does not match the pattern (that specifies for the aforesaid criteria)
# Exit the program, printing "Invalid input"
print("Invalid input")
exit()
numbers_sorted = [] # Create a list that will later be populated with all the numbers in the input, sorted.
letters_sorted = [] # Create a list that will later be populated with all the Letters in the input, sorted.
# Loop through each character in the input.
# .split() splits the input into a list at every space (e.g. "a b c d e f".split() becomes ["a", "b", "c", "d", "e", "f"])
for character in input_.split():
if character.isalpha(): # If the character is alphabetic
# Sort the character into the `letters_sorted` list
# Loop through the length of the list, such that the code in the loop is executed n times,
# where n is the length of `letters_sorted`,
# and the `index` variable starts at 0, and increases per iteration.
for index in range(len(letters_sorted)):
# ord() returns the 'character code' of a character (e.g. ord('a') returns 97, ord('b') returns 98)
# If the `character` (from the outer for loop) is alphabetically preceeding the
# character at position `index` of the `letters_sorted` list,
if ord(letters_sorted[index]) > ord(character):
letters_sorted.insert(index, character) # Insert the `character` (from the outer loop) right before `index` of `letters_sorted`
break # Break from the loop as the character has been sorted into the list
else:
# If the character has not been sorted into the list
# (if the character alphabetically succeeds every other character currently in `letters_sorted`)
letters_sorted.append(character) # Append the character to the very end of the list
else: # Otherwise (in this case, if the character is numeric)
# Sort the character into the `numbers_sorted` list
# See the comments above for sorting alphabetic characters
# The only difference is not using the ord() function as we can directly compare numbers using less-than or greater-than
# (also, we are using the `numbers_sorted` list now)
for index in range(len(numbers_sorted)):
if numbers_sorted[index] > character:
numbers_sorted.insert(index, character)
break
else:
numbers_sorted.append(character)
# Now, the lists are 'in order'.
# Finally, combine the lists to achieve a final list that contains letters sorted, then numbers sorted.
final_list = letters_sorted + numbers_sorted
# (Very) finally, convert the list to a string, separating each list entry by a space character:
final_string = " ".join(final_list)
# (Very very) finally, print the string:
print(final_string)
EDIT: Please any of the other answers above, all of them are much more concise than this one
Related
Implement the function most_popular_character(my_string), which gets the string argument my_string and returns its most frequent letter. In case of a tie, break it by returning the letter of smaller ASCII value.
Note that lowercase and uppercase letters are considered different (e.g., ‘A’ < ‘a’). You may assume my_string consists of English letters only, and is not empty.
Example 1: >>> most_popular_character("HelloWorld") >>> 'l'
Example 2: >>> most_popular_character("gggcccbb") >>> 'c'
Explanation: cee and gee appear three times each (and bee twice), but cee precedes gee lexicographically.
Hints (you may ignore these):
Build a dictionary mapping letters to their frequency;
Find the largest frequency;
Find the smallest letter having that frequency.
def most_popular_character(my_string):
char_count = {} # define dictionary
for c in my_string:
if c in char_count: #if c is in the dictionary:
char_count[c] = 1
else: # if c isn't in the dictionary - create it and put 1
char_count[c] = 1
sorted_chars = sorted(char_count) # sort the dictionary
char_count = char_count.keys() # place the dictionary in a list
max_per = 0
for i in range(len(sorted_chars) - 1):
if sorted_chars[i] >= sorted_chars[i+1]:
max_per = sorted_chars[i]
break
return max_per
my function returns 0 right now, and I think the problem is in the last for loop and if statement - but I can't figure out what the problem is..
If you have any suggestions on how to adjust the code it would be very appreciated!
Your dictionary didn't get off to a good start by you forgetting to add 1 to the character count, instead you are resetting to 1 each time.
Have a look here to get the gist of getting the maximum value from a dict: https://datagy.io/python-get-dictionary-key-with-max-value/
def most_popular_character(my_string):
# NOTE: you might want to convert the entire sting to upper or lower case, first, depending on the use
# e.g. my_string = my_string.lower()
char_count = {} # define dictionary
for c in my_string:
if c in char_count: #if c is in the dictionary:
char_count[c] += 1 # add 1 to it
else: # if c isn't in the dictionary - create it and put 1
char_count[c] = 1
# Never under estimate the power of print in debugging
print(char_count)
# max(char_count.values()) will give the highest value
# But there may be more than 1 item with the highest count, so get them all
max_keys = [key for key, value in char_count.items() if value == max(char_count.values())]
# Choose the lowest by sorting them and pick the first item
low_item = sorted(max_keys)[0]
return low_item, max(char_count.values())
print(most_popular_character("HelloWorld"))
print(most_popular_character("gggcccbb"))
print(most_popular_character("gggHHHAAAAaaaccccbb 12 3"))
Result:
{'H': 1, 'e': 1, 'l': 3, 'o': 2, 'W': 1, 'r': 1, 'd': 1}
('l', 3)
{'g': 3, 'c': 3, 'b': 2}
('c', 3)
{'g': 3, 'H': 3, 'A': 4, 'a': 3, 'c': 4, 'b': 2, ' ': 2, '1': 1, '2': 1, '3': 1}
('A', 4)
So: l and 3, c and 3, A and 4
def most_popular_character(my_string):
history_l = [l for l in my_string] #each letter in string
char_dict = {} #creating dict
for item in history_l: #for each letter in string
char_dict[item] = history_l.count(item)
return [max(char_dict.values()),min(char_dict.values())]
I didn't understand the last part of minimum frequency, so I make this function return a maximum frequency and a minimum frequency as a list!
Use a Counter to count the characters, and use the max function to select the "biggest" character according to your two criteria.
>>> from collections import Counter
>>> def most_popular_character(my_string):
... chars = Counter(my_string)
... return max(chars, key=lambda c: (chars[c], -ord(c)))
...
>>> most_popular_character("HelloWorld")
'l'
>>> most_popular_character("gggcccbb")
'c'
Note that using max is more efficient than sorting the entire dictionary, because it only needs to iterate over the dictionary once and find the single largest item, as opposed to sorting every item relative to every other item.
I would like to get common elements in two given strings such that duplicates will be taken care of. It means that if a letter occurs 3 times in the first string and 2 times in the second one, then in the common string it has to occur 2 times. The length of the two strings may be different. eg
s1 = 'aebcdee'
s2 = 'aaeedfskm'
common = 'aeed'
I can not use the intersection between two sets. What would be the easiest way to find the result 'common' ? Thanks.
Well there are multiple ways in which you can get the desired result. For me the simplest algorithm to get the answer would be:
Define an empty dict. Like d = {}
Iterate through each character of the first string:
if the character is not present in the dictionary, add the character to the dictionary.
else increment the count of character in the dictionary.
Create a variable as common = ""
Iterate through the second string characters, if the count of that character in the dictionary above is greater than 0: decrement its value and add this character to common
Do whatever you want to do with the common
The complete code for this problem:
s1 = 'aebcdee'
s2 = 'aaeedfskm'
d = {}
for c in s1:
if c in d:
d[c] += 1
else:
d[c] = 1
common = ""
for c in s2:
if c in d and d[c] > 0:
common += c
d[c] -= 1
print(common)
You can use two arrays (length 26).
One array is for the 1st string and 2nd array is for the second string.
Initialize both the arrays to 0.
The 1st array's 0th index denotes the number of "a" in 1st string,
1st index denotes number of "b" in 1st string, similarly till - 25th index denotes number of "z" in 1st string.
Similarly, you can create an array for the second string and store the count of
each alphabet in their corresponding index.
s1 = 'aebcdee'
s2 = 'aaeedfs'
Below is the array example for the above s1 and s2 values
Now you can run through the 1st String
s1 = 'aebcdee'
for each alphabet find the
K = minimum of ( [ count(alphabet) in Array 1 ], [ count(alphabet) in Array 2 ] )
and print that alphabet K times.
then make that alphabet count to 0 in both the arrays. (Because if you dint make it zero, then our algo might print the same alphabet again if it comes in the future).
Complexity - O( length(S1) )
Note - You can also run through the string having a minimum length to reduce the complexity.
In that case Complexity - O( minimum [ length(S1), length(S2) ] )
Please let me know if you want the implementation of this.
you can use collection.Counter and count each char in two string and if each char exist in two string using min of list and create a new string by join of them.
from collections import Counter, defaultdict
from itertools import zip_longest
s1 = 'aebcdee'
s2 = 'aaeedfskm'
# Create a dictionary the value is 'list' and can append char in each 'list'
res = defaultdict(list)
# get count of each char
cnt1 = Counter(s1) # -> {'e': 3, 'a': 1, 'b': 1, 'c': 1, 'd': 1}
cnt2 = Counter(s2) # -> {'a': 2, 'e': 2, 'd': 1, 'f': 1, 's': 1, 'k': 1, 'm': 1}
# for appending chars in one step, we can zip count of chars in two strings,
# so Because maybe two string have different length, we can use 'itertools. zip_longest'
for a,b in zip_longest(cnt1 , cnt2):
# list(zip_longest(cnt1 , cnt2)) -> [('a', 'a'), ('e', 'e'), ('b', 'd'),
# ('c', 'f'), ('d', 's'), (None, 'k'),
# (None, 'm')]
# Because maybe we have 'none', before 'append' we need to check 'a' and 'b' don't be 'none'
if a: res[a].append(cnt1[a])
if b: res[b].append(cnt2[b])
# res -> {'a': [1, 2], 'e': [3, 2], 'b': [1], 'd': [1, 1], 'c': [1], 'f': [1], 's': [1], 'k': [1], 'm': [1]}
# If the length 'list' of each char is larger than one so this char is duplicated and we repeat this char in the result base min of each char in the 'list' of count char of two strings.
out = ''.join(k* min(v) for k,v in res.items() if len(v)>1)
print(out)
# aeed
We can use this approach for multiple string, like three strings.
s1 = 'aebcdee'
s2 = 'aaeedfskm'
s3 = 'aaeeezzxx'
res = defaultdict(list)
cnt1 = Counter(s1)
cnt2 = Counter(s2)
cnt3 = Counter(s3)
for a,b,c in zip_longest(cnt1 , cnt2, cnt3):
if a: res[a].append(cnt1[a])
if b: res[b].append(cnt2[b])
if c: res[c].append(cnt3[c])
out = ''.join(k* min(v) for k,v in res.items() if len(v)>1)
print(out)
# aeed
s1="ckglter"
s2="ancjkle"
final_list=[]
if(len(s1)<len(s2)):
for i in s1:
if(i in s2):
final_list.append(i)
else:
for i in s2:
if(i in s1):
final_list.append(i)
print(final_list)
you can also do it like this also, just iterate through both the string using for loop and append the common character into the empty list
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 months ago.
Improve this question
I'm trying to do something like scrabble solver.
letters = ['s','w','r','a']
line_of_dic= ['s','w','r','a','a']
# printing original lists
print("Original list : " + str(line_of_dic))
print("Original sub list : " + str(letters))
# using all() to
# check subset of list
flag = 0
if (all(x in line_of_dic for x in letters)):
flag = 1
# printing result
if (flag):
print("Yes, the word can be created")
else:
print("No, the word cant be.")
This is the part of code that I'm unable to repair, word can't be created, but it prints yes. Is it possible to check if all the letters are in line_of_dic, but if elements are doubled or tripled to check this? Also, is it possible to do without fancy libraries?
You can use dictionary structure. To create dictionary from list you can write a simple code:
letterDict = {}
lineDict = {}
for item in letters:
if item not in letterDict:
letterDict[item] = 1
else:
letterDict[item] += 1
for item in line_of_dic:
if item not in lineDict:
lineDict[item] = 1
else:
lineDict[item] += 1
After that point, you can simply compare two dictionary:
if letterDict == lineDict:
print("Yes, the word can be created")
else:
print("No, the word cant be.")
This can be done on one line by comparing the count of each letter:
flag = 0
if all(line_of_dic.count(char) == letters.count(char) for char in line_of_dic):
flag = 1
Rather than checking if the letter is present, this checks if the count matches.
You need to count the number of each character in each word and then compare the values. You can do this with a dictionary.
ltrs = {}
lod = {}
for char in letters:
ltrs[char] = ltrs.get(char,0) + 1
for char in line_of_dic:
lod[char] = lod.get(char,0) + 1
Then you can see if there are enough of each character to make the word.
In [3]: ltrs
Out[3]: {'a': 1, 'r': 1, 's': 1, 'w': 1}
In [4]: lod
Out[4]: {'a': 2, 'r': 1, 's': 1, 'w': 1}
collections.Counter can make those dictionaries for you.
import collections
ltrs = collections.Counter(letters)
lod = collections.Counter(line_of_dic)
In [6]: ltrs
Out[6]: Counter({'a': 1, 'r': 1, 's': 1, 'w': 1})
In [7]: lod
Out[7]: Counter({'a': 2, 'r': 1, 's': 1, 'w': 1})
Subtracting the Counters you can see if there are enough.
In [31]: lod-ltrs
Out[31]: Counter({'a': 1})
lod has one more 'a' than ltrs.
I am trying to make my program count everything but numbers in a string, and store it in a dictionary.
So far I have this:
string = str(input("Enter a string: "))
stringUpper = string.upper()
dict = {}
for n in stringUpper:
keys = dict.keys()
if n in keys:
dict[n] += 1
else:
dict[n] = 1
print(dict)
I just want the alphabetical numbers quantified, but I cannot figure out how to exclude the non-alphabetical characters.
Basically there are multiple steps involved:
Getting rid of the chars that you don't want to count
Count the remaining
You have several options available to do these. I'll just present one option, but keep in mind that there might be other (and better) alternatives.
from collections import Counter
the_input = input('Enter something')
Counter(char for char in the_input.upper() if char.isalpha())
For example:
Enter something: aashkfze3f8237rhbjasdkvjuhb
Counter({'A': 3,
'B': 2,
'D': 1,
'E': 1,
'F': 2,
'H': 3,
'J': 2,
'K': 2,
'R': 1,
'S': 2,
'U': 1,
'V': 1,
'Z': 1})
So it obviously worked. Here I used collections.Counter to count and a generator expression using str.isalpha as condition to get rid of the unwanted characters.
Note that there are several bad habits in your code that will make your life more complicated than it needs to be:
dict = {} will shadow the built-in dict. So it's better to choose a different name.
string is the name of a built-in module, so here a different name might be better (but not str which is a built-in name as well).
stringUpper = string.upper(). In Python you generally don't use camelCase but use _ to seperate word (i.e. string_upper) but since you only use it to loop over you might as well use for n in string.upper(): directly.
Variable names like n aren't very helpful. Usually you can name them char or character when iterating over a string or item when iterating over a "general" iterable.
You can use re to replace all non-alphabetical characters before doing any manipulation:
regex = re.compile('[^a-zA-Z]')
#First parameter is the replacement, second parameter is your input string
regex.sub('', stringUpper )
string = str(input("Enter a string: "))
stringUpper = string.upper()
dict = {}
for n in stringUpper:
if n not in '0123456789':
keys = dict.keys()
if n in keys:
dict[n] += 1
else:
dict[n] = 1
print(dict)
for n in stringUpper:
if n.isalpha()
dict[n] += 1
else:
dict[n] = 1
print(dict)
You can check string for alphanumeric
n.isalnum()
for aphabetic:
n.isalpha()
So your code will be like:
dict = {}
for n in stringUpper:
if n.isalpha():
keys = dict.keys()
if n in keys:
dict[n] += 1
else:
dict[n] = 1
print(dict)
else:
#do something....
While iterating, check if the lower() and upper() is the same for a character. If they are different from each other, then it is an alphabetical letter.
if n.upper() == n.lower():
continue
This should do it.
This question already has answers here:
Identify strings while removing substrings in python
(3 answers)
Closed 5 years ago.
I have a dictionary as follows.
myfood = {'yummy tim tam': 1, 'tasty chips': 3, 'yummy': 10, 'a loaf of bread': 5}
I also have a set as follows.
myset = {'yummy', 'a', 'tasty', 'of', 'delicious', 'yum'}
Now I want to identify the elements of myset in substrings of myfood and remove them. Hence, my final myfood dictionary should look as follows.
myfood = {'tim tam': 1, 'chips': 3, 'yummy': 10, 'loaf bread':5}
NOTE: I do not want to remove myset elements if they are full strings. E.g., 'yummy': 10 in myfood is not removed as it is not a substring, but a full string.
My current code is as follows.
for word in myfood.keys():
if word in myset:
#Do nothing
else:
######Find the substring part and remove it
Please help me.
Use re.sub to replace only keys that are substrings:
pat = re.compile(r'|'.join([r'(\s|\b){}\b'.format(x) for x in myset]))
dct = {}
for k, v in myfood.items():
if k not in myset: # exclude full strings
k = pat.sub('', k).strip()
dct[k] = v
print(dct)
# {'yummy': 10, 'loaf bread': 5, 'tim tam': 1, 'chips': 3}