3

Imagine a dice roller where you want to print the result with good grammar.

  • 'You rolled a 18' is an example of bad grammar.
  • 'You rolled an 18' is an example of good grammar.
  • 'You rolled an 5' would be bad grammar.

I could define a function that does a pile of if statements but that doesn't seem Pythonic.

#ideally something like this 
print(f'You rolled {a-or-an} {someint}')
pault
  • 41,343
  • 15
  • 107
  • 149
  • Natural language isn't simple. You need to create some sort of mapping between numbers and the article to use based on the initial sound in the name of the number. That could be a function or a `dict`, but you need to define it yourself. – chepner May 17 '19 at 18:15
  • 1
    You only need one if statement: `if someint < 10: a-or-an = 'a'` – Max May 17 '19 at 18:16
  • @Max "You rolled an 7"? – chepner May 17 '19 at 18:16
  • @chepner wrong way – Max May 17 '19 at 18:17
  • 2
    @Max It's not the size of the number that is the issue: it's the *sound* the name of the number starts with. You wouldn't say "You rolled an 15". – chepner May 17 '19 at 18:17
  • For a general solution you can convert the roll [integer into a word](https://stackoverflow.com/a/8982414/5858851) and then check if that word starts with a vowel. However, if you knew the max and min rolls allowed you can enumerate the ones that require `"an"` and have a special case for them. – pault May 17 '19 at 18:18
  • @chepner my bad, i stopped at `11` and assumed true for rest – Max May 17 '19 at 18:20
  • @pault Even that doesn't quite work: "You rolled a 100", not "You rolled an 100". (Assuming you say "one hundred", not "hundred".) – chepner May 17 '19 at 18:21
  • @chepner special case for in the first word is `"one"` (you wouldn't say "You rolled an 1" either) – pault May 17 '19 at 18:23
  • 1
    Vocal experimentation suggests you only need an `'an'` when the number in word form begins with an `'ei'` – Max May 17 '19 at 18:24
  • 1
    @Max so maybe `print("You rolled %s %d" % ("an" if someint == 18 or str(someint)[0] == '8' else "a", someint))` – pault May 17 '19 at 18:27
  • My condition is still true, if you examine it word form, if the word begins with 'ei' like 'eighteen' or 'eighty' it works, it doesnt work just looking at the integers – Max May 17 '19 at 18:29
  • Omitting the article would also be grammatical: You rolled 11. You rolled 12. – chepner May 17 '19 at 18:41
  • 1
    For the benefit of those coming here to find software to generate a or an, correct except for rare cases, given the following word as a string, a comprehensive solution in 116 lines is at https://github.com/Kaivosukeltaja/php-indefinite-article . This was a port of a Python function to do the same thing. All the various cases are clearly presenting in this function, so you can extract only what you need. – David Spector Jul 26 '20 at 17:04

3 Answers3

3

Based on the discussion in the comments, I think the following would work for you:

def getDiceRollString(someint):
    a_or_an = "an" if someint in (11, 18) or str(someint)[0] == '8' else "a"
    return "You rolled %s %d" % (a_or_an, someint)

You can try it out:

for i in [1, 5, 8, 11, 15, 18, 28, 81, 88, 800]:
    print(getDiceRollString(i))
#You rolled a 1
#You rolled a 5
#You rolled an 8
#You rolled an 11
#You rolled a 15
#You rolled an 18
#You rolled a 28
#You rolled an 81
#You rolled an 88
#You rolled an 800
chepner
  • 497,756
  • 71
  • 530
  • 681
pault
  • 41,343
  • 15
  • 107
  • 149
  • 2
    I'd say that this most elegant, I'd also like to think that I contributed to this answer aha. – Max May 17 '19 at 18:44
2

If you use num2word (installed by pip install num2word)

import num2word
a-or-an ='an' if numtoword.to_card(someint)[0] == 'e' else 'a'

Unfortunately because its based on sounds, and sounds are based on words, I don't think there is a way of doing this by examining integers thus the solution isn't very pythonic.

Also feel free to disprove this (as I don't know)

Previous was disproved in the comments below by 11, this should now be fixed.

Max
  • 729
  • 5
  • 15
2

Here's my un-optimized idea. Going off of the other answers and converting to English, then changing the article (a/an) based on the first letter, if it's a vowel. Except for o in one because the word one actually sounds like won where there is a consonant w as the first sound.

Anywho, here's my idea.

from random import randint

import inflect # python -m pip install inflect

p = inflect.engine()

numlist = [1,7,8,10,11,12,11000000]

#for i in range(0, 10):
for i in numlist:
    article = 'a'
    num = i #randint(0, 10000000000)
    numword = p.number_to_words(num)
    if numword[:1] in 'aeiu':
        article = 'an'

    print("You rolled ", article, " ", num, " (", numword, ")", sep='')
ahogen
  • 759
  • 8
  • 20