I am trying to make some code where the user inputs a sentence, the sentence is turned into a dict and then the dict is used to get the original sentence back.
Code:
import json
def code():
sentence = input("Please write a sentence: ")
dictionary = {v: k for k,v in enumerate(sentence.split(), start=1)}
with open('Dict.txt', 'w') as fp:
json.dump(dictionary, fp)
print(dictionary)
puncList = ["{","}",",",":","'","[","]","1","2","3","4","5"]
for i in puncList:
for sentence in dictionary:
dictionary=[sentence.replace(i," ") for sentence in dictionary]
print(' '.join(dictionary))
code()
Input:
Hello my name is Bob
Actual output:
{'Hello' : '1', 'name' : '3', 'Bob' : '5', 'my' : '2', 'is' : '4'}
Hello name Bob my is
Desired output:
{'Hello' : '1', 'name' : '3', 'Bob' : '5', 'my' : '2', 'is' : '4'}
Hello my name is Bob
This would be fine too:
{'Hello' : '1', 'my' : '2', 'name' : '3', 'is' : '4', 'Bob' : '5'}
Hello my name is Bob
For the part where I recreate the original sentence, it cant just print the sentence, it has to be from the dict.
You need to either use OrderedDict to retain the element order, or sort the dictionary elements before you print them out. You've already got an OrderedDict answer, so here's how to use the dict you created:
print(' '.join(k for (k, v) in sort(dictionary.items(), key=lambda x: x[1])))
Incidentally, your approach has a bug: If you apply it to a sentence with repeated words, e.g., "boys will be boys", you'll find that there's no element with index 1 in your dictionary since (boys, 4) will overwrite (boys, 1).
Use an OrderedDict on enumerate, like so:
from collections import OrderedDict
s = "Hello my name is Bob"
d = OrderedDict((v, i) for i, v in enumerate(s.split(), 1))
print(d)
# OrderedDict([('Hello', 1), ('my', 2), ('name', 3), ('is', 4), ('Bob', 5)])
s_rebuild = ' '.join(d)
print(s_rebuild)
# 'Hello my name is Bob'
Since the dictionary is already ordered, the values are not used for rebuilding the string.
You logic is flawed in that it can't handle sentences with repeated words:
Hello Bob my name is Bob too
{'name': 4, 'Hello': 1, 'Bob': 6, 'is': 5, 'too': 7, 'my': 3}
name Hello Bob is too my
We can deal with that using a defaultdict, making the values arrays of word positions instead of individual numbers. We can further improve things by dealing with your punch list up front via a split. Finally, we can reconstruct the original sentence using a pair of nested loops. We don't want/need an OrderedDict, or sorting, to do this:
import re
import json
from collections import defaultdict
PUNCH_LIST = r"[ {},:'[\]1-5]+"
def code():
dictionary = defaultdict(list)
sentence = input("Please write a sentence: ")
for position, word in enumerate(re.split(PUNCH_LIST, sentence), start=1):
dictionary[word].append(position)
with open('Dict.txt', 'w') as fp:
json.dump(dictionary, fp)
print(dictionary)
position = 1
sentence = []
while position:
for word, positions in dictionary.items():
if position in positions:
sentence.append(word)
position += 1
break
else:
position = 0
print(' '.join(sentence))
code()
EXAMPLE:
Please write a sentence: Hello Bob, my name is Bob too
defaultdict(<class 'list'>, {'is': [5], 'too': [7], 'Bob': [2, 6], 'Hello': [1], 'name': [4], 'my': [3]})
Hello Bob my name is Bob too
Where Dict.txt contains:
{"is": [5], "too": [7], "Bob": [2, 6], "Hello": [1], "name": [4], "my": [3]}
Note that the defaultdict is a convenience, not a requirement. A plain dictionary will do, but you'll have to initialize the lists for each key.
Related
I have a list of words (listwords = ['a', 'b', 'c']) and a previously original dict (dictwords = {'111': '['a', 'a', 'b']', '112': '['b', 'a', 'b']'}) whose purpose is to create a new dict where the keys will be the listwords and their elements will be the quantity one. extra identification and how many words occur in the original dict. The code looks like this:
for i in listwords:
addlist= []
for k, x in dictwords.items():
if i in x:
cont = 0
cont = x.count(i)
addlist.append(k)
addlist.append(cont)
newdict[i] = addlist
The end result should be this below:
a -> ['111', 2], ['112', 1]
b -> ['111', 2], ['112', 1]
c -> ['111', 0], ['112', 0]
i.e. it was supposed to be a key with its respective count lists in the new dict, but the result that is coming out is this:
a -> ['111', 2, '112', 1]
b -> ['111', 2, '112', 1]
c -> ['111', 0, '112', 0]
Does anyone know where I am going wrong? Should I insert a new list and thus insert in the new dict?
You do not have to iterate over the subarrays, your .count does that for you. Instead, loop over the keys in listwords so that you don't have to check multiple times for the same character.
Try this instead:
for i in listwords:
addlist= []
for k, x in dictwords.items():
addlist.append({k: x.count(i)})
newdict[i] = addlist
>>> newdict
{'a': [{'111': 2}, {'112': 1}], 'b': [{'111': 1}, {'112': 2}], 'c': [{'111': 0}, {'112': 0}]}
You can also use a simple list/dict comprehension to accomplish your goals:
>>> {i: [{key: dictwords[key].count(i)} for key in dictwords] for i in listwords}
{'a': [{'111': 2}, {'112': 1}], 'b': [{'111': 1}, {'112': 2}], 'c': [{'111': 0}, {'112': 0}]}
Does anyone know where I am going wrong? Should I insert a new list and thus insert in the new dict?
You don't need to insert a new list per se, you just need to change where you're initializing addlist. Assuming you want a list of lists, you need to initialize addlist for every key in dictwords. That means moving addlist = [] under for k, x in dictwords.items():.
Now, instead of assigning addlist to a key in newdict, you need to have newdict create a list for each letter in listwords and append addlist to the list for each letter. There are a couple of different ways to do this, but a pretty elegant solution would be to use defaultdict from the collections module. Using defaultdict and moving the definition of addlist, you should look like this:
from collections import defaultdict
listwords = ['a', 'b', 'c']
dictwords = {'111': "['a', 'a', 'b']", '112': "['b', 'a', 'b']"}
newdict = defaultdict(list)
for i in listwords:
for k, x in dictwords.items():
addlist= []
if i in x:
cont = 0
cont = x.count(i)
addlist.append(k)
addlist.append(cont)
newdict[i].append(addlist)
And printing newdict should give you something like this:
defaultdict(<class 'list'>, {'a': [['111', 2], ['112', 1]], 'b': [['111', 1], ['112', 2]]})
You can of course make the output more pretty for your purposes.
You are right. Right now all the entries are referring to the same list, and you're mutating it.
occurences = {}
for word in list_of_words:
list_to_store = []
for key, words in dict_of_words.items():
list_to_store.append((key, words.count(word)))
occurences[word] = list_to_store
You could also use a list comprehension:
occurences = {}
for word in list_of_words:
occurences[word] = [(key, words.count(word))
for key, words in dict_of_words.items()]
You can also combine it with a dict comprehension:
occurences = {
word: [(key, words.count(word))
for key, words in dict_of_words.items()]
for word in list_of_words
}
And this looks much more concise.
Output code:
for k, v in occurences.items():
print(f"{k} -> {v}")
Output:
a -> [('111', 2), ('112', 1)]
b -> [('111', 1), ('112', 2)]
c -> [('111', 0), ('112', 0)]
I have this code that should run through the keys in the python defaultdict, and if the key isn't in the defaultdict, it gets added.
I'm getting an error that I don't encounter with regular defined dictionaries, and I'm having a bit of trouble working it out:
The code:
from collections import defaultdict
def counts(line):
for word in line.split():
if word not in defaultdict.keys():
word = "".join(c for c in word if c not in ('!', '.', ':', ','))
defaultdict[word] = 0
if word != "--":
defaultdict[word] += 1
The error:
if word not in defaultdict.keys():
TypeError: descriptor 'keys' of 'dict' object needs an argument
You did not construct a defaultdict object here, you simply refer to the defaultdict class.
You can create one, like:
from collections import defaultdict
def counts(line):
dd = defaultdict(int)
for word in line.split():
word = ''.join(c for c in word if c not in ('!', '.', ':', ','))
if word not in dd:
dd[word] = 0
if word != '--':
dd[word] += 1
return dd
That being said, you probably want to use a Counter here, like:
from collections import Counter
def counts(line):
words = (
''.join(c for c in word if c not in ('!', '.', ':', ',')) for word in line.split()
)
return Counter(
word for word in words if word != '--'
)
defaultdict is a class; you need an object:
from collections import defaultdict
def counts(line, my_dict):
for word in line.split():
if word not in my_dict.keys():
word = "".join(c for c in word if c not in ('!', '.', ':', ','))
my_dict[word] = 0
if word != "--":
my_dict[word] += 1
my_dict = defaultdict()
counts("Now is the time for all good parties to come to the aid of man.", my_dict)
print(my_dict)
Output:
defaultdict(None, {'Now': 1, 'is': 1, 'the': 2, 'time': 1, 'for': 1, 'all': 1, 'good': 1, 'parties': 1, 'to': 2, 'come': 1, 'aid': 1, 'of': 1, 'man': 1})
For example, the dictionary may be
{'Cat': 'Dog', 'Bird': 'Mouse'}
And when the user input
'There is a cat'
The output would be
'There is a dog'
I tried replacing it with the value but it clearly doesn't work with dict.
Please help.
given a pair of <key:value>, you just need to access the dict in the key index to get the value:
d = {'Cat': 'Dog', 'Bird': 'Mouse'}
user_input = 'There is a cat'
# use split() to split string into words
# use [-1] to get last word ('cat')
#print(d[user_input.split()[-1]]) # would fail, since "cat" isn't inside the dict
user_input = 'There is a Cat'
print("There is a", d[user_input.split()[-1]]) # This time it would work. Output "There is a Dog"
OR ''.join joining a string split woth dictionary get method:
d = {'Cat': 'Dog', 'Bird': 'Mouse'}
s='There is a cat'
s2=' '.join(d.get(i.title(),i) for i in s.split())
print(s2)
Output:
There is a Dog
You need to iterate over the keys inside dict and check with the given input. If it is present you can replace it with the corresponding value.
d = {'Cat': 'Dog', 'Bird': 'Mouse'}
inp = 'There is a Cat'
for key,value in d.items():
if key in inp:
inp = inp.replace(key,value)
print(inp)
'There is a Dog'
Please note that conditionals are case-sensitive. You can convert strings to same case with str.lower() if you are looking for case-insensitive checks.
You can split the string into words, replace each word with the the corresponding value in the dict if the word is an index, and then join the words into a string:
d = {'Cat': 'Dog', 'Bird': 'Mouse'}
s = 'There is a Cat'
print(' '.join(d.get(w, w) for w in s.split()))
This outputs:
There is a Dog
Here's a one-liner.
d = {'cat': 'dog', 'bird': 'mouse'}
input_ = 'There is a cat'
output = ' '.join([x if x not in d else d[x] for x in input_.split()])
>> print (output)
>> There is a dog
BREAK DOWN
input_.split() splits the input into a list of words.
[ ] create a new list
for x in input_.split() for every word in the input string
x if x not in d add all the words that can't be found in dict.
else d[x] for any word that is found in dic, instead of adding the word, add the according value from the dict
' '.join([]) join all the words in the list with a space between each word.
what i am trying to do :
dict that maps each word that appears in the file
to a list of all the words that immediately follow that word in the file.
The list of words can be be in any order and should include
duplicates.So for example the key "and" might have the list
["then", "best", "then", "after", ...] listing
all the words which came after "and" in the text.
f = open(filename,'r')
s = f.read().lower()
words = s.split()#list of words in the file
dict = {}
l = []
i = 0
for word in words:
if i < (len(words)-1) and word == words[i]:
dict[word] = l.append(words[i+1])
print dict.items()
sys.exit(0)
collections.defaultdict is helpful for such iterations. For simplicity, I've invented a string rather than loaded from a file.
from collections import defaultdict
import string
x = '''This is a random string with some
string elements repeated. This is so
that, with someluck, we can solve a problem.'''
translator = str.maketrans('', '', string.punctuation)
y = x.lower().translate(translator).replace('\n', '').split(' ')
result = defaultdict(list)
for i, j in zip(y[:], y[1:]):
result[i].append(j)
# result
# defaultdict(list,
# {'a': ['random', 'problem'],
# 'can': ['solve'],
# 'elements': ['repeated'],
# 'is': ['a', 'so'],
# 'random': ['string'],
# 'repeated': ['this'],
# 'so': ['that'],
# 'solve': ['a'],
# 'some': ['string'],
# 'someluck': ['we'],
# 'string': ['with', 'elements'],
# 'that': ['with'],
# 'this': ['is', 'is'],
# 'we': ['can'],
# 'with': ['some', 'someluck']})
You can use defaultdict for this:
from collections import defaultdict
words = ["then", "best", "then", "after"]
words_dict = defaultdict(list)
for w1,w2 in zip(words, words[1:]):
words_dict[w1].append(w2)
Results:
defaultdict(<class 'list'>, {'then': ['best', 'after'], 'best': ['then']})
dictionary = {'0': "Linda", "1": "Anna", "2": 'Theda', "3":'Thelma',"4": 'Thursa',"5" :"Mary"}
dictionary2 = ['Linda', 'Ula', 'Vannie', 'Vertie', 'Mary']
I want to remove the same values from dictionary to dictionary2, I wrote the code like this:
[k for k, v in dictionary.items() if v not in dictionarya]
But it still can print out the words above same words, like this:
['0', '1', '2', '3', '4']
How to remove all the repeat words? so it can print out like this: e,g.
['1', '2', '3', '4']
How to just get the last loop? Thank you
To get the keys in which the values aren't contained in the other list you can use the following list comprehension
>>> [k for k,v in dictionary.items() if v not in dictionary2]
['2', '4', '3', '1']
Just do the following list comprehension:
>>> dictionary = {'0': "Linda", "1": "Anna", "2":"Mary"}
>>> dictionary2 = ['Linda', 'Theda', 'Thelma', 'Thursa', 'Ula', 'Vannie', 'Vertie', 'Mary']
>>> value = [i for i in dictionary2 if i not in dictionary.values()]
>>> value
['Theda', 'Thelma', 'Thursa', 'Ula', 'Vannie', 'Vertie']
>>>
This works:
dictionary = {'0': "Linda", "1": "Anna", "2":"Mary"}
dictionary2 = ['Linda', 'Theda', 'Thelma', 'Thursa', 'Ula', 'Vannie', 'Vertie', 'Mary']
# I want to remove the same values from dictionary to dictionary2, I wrote the code like this:
output = [i for i in dictionary2 if i not in dictionary.values()]
Result:
['Theda', 'Thelma', 'Thursa', 'Ula', 'Vannie', 'Vertie']
You could convert dictionary2 to a set, and use this syntax:
>>> dictionary = {'0': "Linda", "1": "Anna", "2": 'Theda', "3":'Thelma',"4": 'Thursa',"5" :"Mary"}
>>> dictionary2 = ['Linda', 'Ula', 'Vannie', 'Vertie', 'Mary']
>>> remove_names = set(dictionary2)
>>> [name for name in dictionary.values() if name not in remove_names]
['Anna', 'Theda', 'Thelma', 'Thursa']
>>> [id for id, name in dictionary.items() if name not in remove_names]
['1', '2', '3', '4']
Note that dictionary2 isn't a dict but a list.
Also, Python dicts are unordered. You cannot be sure that the result will always be 1,2,3,4.
Finally, if all your dict keys are integers (or look like integers), you'd better use a list :
>>> names = ["Linda","Anna",'Theda','Thelma','Thursa',"Mary"]
>>> remove_names = set(['Linda', 'Ula', 'Vannie', 'Vertie', 'Mary'])
>>> list(enumerate(names))
[(0, 'Linda'), (1, 'Anna'), (2, 'Theda'), (3, 'Thelma'), (4, 'Thursa'), (5, 'Mary')]
>>> [name for name in names if name not in remove_names]
['Anna', 'Theda', 'Thelma', 'Thursa']
>>> [id for id, name in enumerate(names) if name not in remove_names]
[1, 2, 3, 4]
This should be more readable and faster than your code.
dictionary = {'0': "Linda", "1": "Anna", "2":"Mary"}
dictionary2 = ['Linda', 'Theda', 'Thelma', 'Thursa', 'Ula','Vannie','Vertie', 'Mary']
for i in range(0, len(dictionary2)-1):
if dictionary2[i] in dictionary.values():
del dictionary2[i]
print (dictionary2)
Prints this:
['Theda', 'Thelma', 'Thursa', 'Ula', 'Vannie', 'Vertie']