Python Forum
General Programming Question with Dictionary - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: General Programming Question with Dictionary (/thread-35989.html)

Pages: 1 2


General Programming Question with Dictionary - giddyhead - Jan-07-2022

I have a dictionary that contains books names, numbers of pages, who wrote the book, etc. What I attempting to do is search the whole dictionary for all the numbers for example 1,56,54 and even numbers as such 1894-3999 RT and replace/update them with the spelling of the numbers.
I came up with the following after trying different combinations :
value  = re.findall(r'[0-9]+', str(cybc)) #Find all the numbers in dictionary
for t in value: #Loop through Values
    cybc.update(num2words(int(t))) #Update Dictionary with new values
    print('With Words',num2words(int(t))) # Print the spelled out words
However when ran I get the following error message:
ValueError: dictionary update sequence element #0 has length 1; 2 is required
What are the final steps to finish this? As I know there is something small to finish it but I cannot seem to figure it out. Thanks.


RE: General Programming Question with Dictionary - bowlofred - Jan-07-2022

A dictionary is a set of key/value pairs. You have to tell the dictionary which key you are trying to update. Your program just shoves a new value at it.

But assuming cybc is your dictionary, then str(cybc) is just a big string of all the keys and values (and some punctuation) smushed together. So when you're handed a string, you can't tell what part of the dictionary it came from.

If the key has digits in it, do you want to change the key, or do you just want to change the values?


RE: General Programming Question with Dictionary - giddyhead - Jan-07-2022

(Jan-07-2022, 06:08 AM)bowlofred Wrote: A dictionary is a set of key/value pairs. You have to tell the dictionary which key you are trying to update. Your program just shoves a new value at it.

But assuming cybc is your dictionary, then str(cybc) is just a big string of all the keys and values (and some punctuation) smushed together. So when you're handed a string, you can't tell what part of the dictionary it came from.

If the key has digits in it, do you want to change the key, or do you just want to change the values?

Oh Ok I see I am trying to figure that one out right now to only change the values only.


RE: General Programming Question with Dictionary - bowlofred - Jan-07-2022

Then the right way to do this is to grab each of the key/value pairs, examine the value and if it needs changing, update it by setting the key to have a new value.

for key, value in cybc.items():
    # evaluate/change the value
    cybc[key] = updated_value(value) # updated_value() needs to return the correct value for your update
The other concern I have is that the value might have a part of a number in it, but your current technique would throw away all the non-number parts. Is that what you want? Or it might have multiple numbers. Let's say one of your values is the string "1894-3999 RT". What do you want the new value to be? It can't be two integers. It could be one of the integers, or it could be a list or a tuple with both integers, or... ?


RE: General Programming Question with Dictionary - giddyhead - Jan-07-2022

(Jan-07-2022, 07:54 AM)bowlofred Wrote: Then the right way to do this is to grab each of the key/value pairs, examine the value and if it needs changing, update it by setting the key to have a new value.

for key, value in cybc.items():
    # evaluate/change the value
    cybc[key] = updated_value(value) # updated_value() needs to return the correct value for your update
The other concern I have is that the value might have a part of a number in it, but your current technique would throw away all the non-number parts. Is that what you want? Or it might have multiple numbers. Let's say one of your values is the string "1894-3999 RT". What do you want the new value to be? It can't be two integers. It could be one of the integers, or it could be a list or a tuple with both integers, or... ?

Thanks for the information and insight. What I seeking is to look through all the values and if it has a digit for example 1,5,56 or in strings like "1894-3999 RT" , "They are 75 Artist 2 pending" update the values to one, five, fifty-six and in the strings "one thousand, eight hundred and ninety-four-three thousand, nine hundred and ninety-nine RT" and "They are seventy-five Artist two pending". Thanks


RE: General Programming Question with Dictionary - bowlofred - Jan-07-2022

So you'll need to create a parser for that, and I'm not sure it will be easy unless you already know your input will be restricted to certain types. Here's a couple of items that might be challenging to distinguish:

"The car was priced at $52,400."
"I've got red, green, and blue, with 100,200, and 75 respectively"

You might take a look at https://pypi.org/project/inflect/. It can turn numbers (or strings of digits) into english terms (assuming you've already parsed the correct number).

>>> import inflect
>>> p = inflect.engine()
>>> p.number_to_words(52400)
'fifty-two thousand, four hundred'
>>> p.number_to_words("52400")
'fifty-two thousand, four hundred'



RE: General Programming Question with Dictionary - giddyhead - Jan-07-2022

(Jan-07-2022, 07:01 PM)bowlofred Wrote: So you'll need to create a parser for that, and I'm not sure it will be easy unless you already know your input will be restricted to certain types. Here's a couple of items that might be challenging to distinguish:

"The car was priced at $52,400."
"I've got red, green, and blue, with 100,200, and 75 respectively"

You might take a look at https://pypi.org/project/inflect/. It can turn numbers (or strings of digits) into english terms (assuming you've already parsed the correct number).

>>> import inflect
>>> p = inflect.engine()
>>> p.number_to_words(52400)
'fifty-two thousand, four hundred'
>>> p.number_to_words("52400")
'fifty-two thousand, four hundred'

Oh here is the updated code information:

from num2words import num2words

cybc = {col[0]: col[1:] for col in zip(*sheet.values) }

for key, value in cybc.items():
    if value == re.findall(r'[0-9]+', str(cybc)):
          cybc[key] = re.sub(r"[0-9]+",  num2words(int(value)) ,str(cybc))
          print('Test to show updated value', value)
          print('Test to show keys', key)
I just ran the code but it does not print anything and I just remembered that the only key that do not want modified is the key Book Names all others can be changed.


RE: General Programming Question with Dictionary - bowlofred - Jan-07-2022

Line 6 won't work. You're asking if the current value is a match object. I presume that your current values are strings, so that won't ever succeed.

You're using "findall", but findall only hands you the bits that match, not the non-digit bits (which you presumably want to retain). Possibly you want to use re.sub instead. Then if your num2words can take a match object instead of an int, you could write it as:

sub match2words(m):
    digits = m.group()
    # convert this with whatever means you have
    return "converted"

for key, value in cybc.items():
    new_value = re.sub(r'\d+', match2words, value)
    cybc[key] = new_value
    print('Test to show updated value', new_value)
    print('Test to show keys', key)



RE: General Programming Question with Dictionary - Pedroski55 - Jan-07-2022

Can you post your an excerpt from your dictionary, maybe 3 or 4 key:value pairs?

That would make things clearer for me.


RE: General Programming Question with Dictionary - giddyhead - Jan-07-2022

(Jan-07-2022, 10:57 PM)Pedroski55 Wrote: Can you post your an excerpt from your dictionary, maybe 3 or 4 key:value pairs?

That would make things clearer for me.

Please see below:
for key, value in cybc.items():
    print('Key',key, '->', 'Value',value ,'\n')
 
Key BookNumber -> Value (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)
Key Book Names -> Value ('For Whom the Bell Tolls', 'Brave New World', 'Nineteen Eighty-Four', 'The Sound and the Fury', 'Gone with the Wind', "Lady Chatterley's Lover", 'The Hound of the Baskervilles', 'I Am Number 4', 'The Great Gatsby', 'The War of the Worlds', 'The Lord of the Rings', 'Martin Eden', 'On the Road', "A Room of One's Own", 'Lord Jim', 'Manhattan Transfer', "Sophie's Choice", 'The Catcher in the Rye', 'No Orchids For Miss Blandish', 'The Origins of Totalitarianism The Burden of Our Time', 'Fahrenheit 451')
Key Pages -> Value (None, 311, 328, 326, '1037 (first edition), 1024 (Warner Books Paperback)', None, None, 440, None, 287, 'original manuscripts, which total 9,250 pages', None, 320, 172, None, None, 562, 234, None, 704, 256)
Key Written Time/Published -> Value (1940, 1932, 1949, 1929, 1936, 1928, '1901–02', 2009, 1925, 1898, '1954–55', 1909, 1957, 1929, 1900, 1925, 1979, 1951, 1939, 1951, 1953)
Key Authors -> Value ('Ernest Hemingway', 'Aldous Huxley', 'George Orwell', 'William Faulkner', 'Margaret Mitchell', 'D.H. Lawrence', 'Arthur Conan Doyle', 'Jobie Hughes, James Frey', 'F. Scott Fitzgerald', 'H.G. Wells', 'J.R.R. Tolkien', 'Jack London', 'Jack Kerouac', 'Virginia Woolf', 'Joseph Conrad', 'John Dos Passos', 'William Styron', 'J.D. Salinger', 'James Hadley Chase', 'Hannah Arendt', 'Ray Bradbury')