22
\$\begingroup\$

Background

The Italian definite article (corresponding to English the) has seven different forms: l', il, lo, gli, i, la, le. Which one to use depends on three variables:

  • Gender: masculine / feminine.
  • Number: singular / plural.
  • Initial letter of the subsequent word: vowel / consonant type A / consonant type B.
    • Vowel is any of these: aeiou.
    • Consonant type B is any of these cases: s- followed by another consonant, z-, gn-, pn-, ps-, x-, i- followed by vowel (this i acts as a semivowel).
    • Consonant type A is a consonant that is not type B.

The table shows the article form to be used in each of the twelve combinations of the three above variables. Note that the l' form is attached to the following word with a single quote and without a space.

enter image description here

The challenge

Input a word and one or two strings, numbers or Booleans indicating gender and number. (The initial letters will have to be obtained from the input word).

The input word will be a sequence of lowercase ASCII letters. Accented vowels will be replaced by their non-accented versions (for example, realtà will be input as realta).

The gender and number inputs can be separate numbers, Booleans or strings, or a combined number of string (for example, 1 for masculine singular, 2 for feminine singular, etc).

Any reasonable format and separator can be used, as long as it is specified in the answer.

Output the word preceded by the appropriate form of the article, with space or single quote as needed. The output should also be lowercase. Trailing or leading blank space is allowed.

Code golf, shortest wins.

Test cases

In the following I use the input letters m, f to specify gender, and s, p for number (this is just one possible input format).

Input               Output              Comment

macchina f s        la macchina         Initial letter is cons. A
zio m s             lo zio              Initial letter is cons. B
libri m p           i libri             Initial letter is cons. A
ieri m s            lo ieri             Initial letter is cons. B
aquile f p          le aquile           Initial letter is vowel
spagnoli m p        gli spagnoli        Initial letter is cons. B
golf m s            il golf             Initial letter is cons. A
ombra f s           l'ombra             Initial letter is vowel
impossibili m p     gli impossibili     Initial letter is vowel
\$\endgroup\$
14
  • \$\begingroup\$ You may want to also make a challenge on the coniugation of regular verbs. \$\endgroup\$ Jul 16, 2016 at 9:31
  • \$\begingroup\$ @user6245072 Well, there's already this... the difference would probably be too small \$\endgroup\$
    – Luis Mendo
    Jul 16, 2016 at 9:49
  • 1
    \$\begingroup\$ A minor technical niggle: /j/ is normally called a semivowel in English, not a semiconsonant. I wonder what the solutions would be if they were to factor in edge cases like ⟨ch⟩ representing [ʃ] rather than [k] (lo chef, lo chardonnay), the variation with French names (l’Havet but lo Hugo), fossilised forms (gli dei, per lo meno), women referred to by their last name (l’Antonia but la Antonini), etc. That would be quite the formidable thing to golf-code. \$\endgroup\$ Jul 16, 2016 at 19:56
  • 1
    \$\begingroup\$ As Italian I ask you to take off ieri test case because is an adverb and not a noun! (BTW it was formally correct) Please! \$\endgroup\$ Jul 18, 2016 at 14:40
  • 1
    \$\begingroup\$ We usally say: "Non pensare a ieri, Pensa a Domani" \$\endgroup\$ Jul 18, 2016 at 15:27

7 Answers 7

7
\$\begingroup\$

Retina, 138 133 129 113 bytes

^.(s[^aeiou]|z|gn|pn|ps|x|i[aeiou])
B$&
^.[aeiou]
V$&
^\d.
A$&
V[02]
l'
A0
il 
B0
lo 
A1
i 
.1
gli 
.2
la 
.3
le 

Test suite. (prepended %(G`\n to run all test-cases at once)

Input format: macchina f s becomes 2macchina instead.

0: Masculine Singular
1: Masculine Plural
2: Feminine Singular
3: Feminine Plural

Conversion table thanks to Kevin Lau.

\$\endgroup\$
0
4
\$\begingroup\$

Python 3.5, 238 235 192 181 178 bytes:

(-13 bytes thanks to tips from Leaky Nun!)

import re;R=re.match;lambda a,b:(R('s[^aeiou]|(z|gn|pn|ps|x|i)[aeiou]',a)and['lo ','gli ','la '][b]or R('[aeiou]',a)and["l'",'gli '][b%2]or['il ','i ','la '][b]if b<3else'le ')+a

An anonymous lambda function that takes arguments in the form of (<String>, <Integer Gender-Plurality mapping>), where the mapping is as follows:

0 -> Masculine Singular
1 -> Masculine Plural
2 -> Feminine Singular
3 -> Feminine Plural

To call it, simply give the function any valid name, and then call it like a normal function wrapped inside a print statement. Therefore, if the question were to be named U, simply call it like print(U(<String>, <Integer Gender-Plurality mapping>)).

Try It Online! (Ideone)

\$\endgroup\$
9
  • \$\begingroup\$ zzz and yyy or xxx is two bytes shorter than [xxx,yyy][bool(zzz)] \$\endgroup\$
    – Leaky Nun
    Jul 16, 2016 at 14:16
  • \$\begingroup\$ @LeakyNun I can do that? Wow, I did not even know. Thanks! :) \$\endgroup\$
    – R. Kap
    Jul 16, 2016 at 18:13
  • \$\begingroup\$ It works as long as yyy is truthy. \$\endgroup\$
    – Leaky Nun
    Jul 16, 2016 at 18:18
  • \$\begingroup\$ @LeakyNun Yeah, of course. \$\endgroup\$
    – R. Kap
    Jul 16, 2016 at 18:31
  • \$\begingroup\$ ["l'",'gli '][b%2] is 3 bytes shorter than ["l'",'gli ',"l'"][b] \$\endgroup\$
    – Leaky Nun
    Jul 16, 2016 at 18:47
4
\$\begingroup\$

Java, 227 208 195 bytes

-13 bytes thanks to Leaky Nun

String f(String a,int o){boolean v=a.matches("^([aeou]|i[^aeiou]).*"),b=a.matches("^([ixz]|gn|pn|ps|s[^aeiou]).*");return(o>1?o>2?"le ":v?"l'":"la ":o>0?v||b?"gli ":"i ":v?"l'":b?"lo ":"il ")+a;}

Takes your string and an int based on the following mapping:

0: Masculine Singular
1: Masculine Plural
2: Feminine Singular
3: Feminine Plural

Returns a string with the result.

Ungolfed with test cases and with no ternary operators (for real now):

class Test {

    public static String f(String a, int o) {
        boolean v = a.matches("^([aeou]|i[^aeiou]).*");
        boolean b = a.matches("^([ixz]|gn|pn|ps|s[^aeiou]).*");
        String r;
        if(o > 1)
            if(o > 2)
                r = "le ";
            else
                if(v)
                    r = "l'";
                else
                    r = "la ";
        else
            if(o > 0)
                if(v || b)
                    r = "gli ";
                else
                    r = "i ";
            else
                if(v)
                    r = "l'";
                else if(b)
                    r = "lo ";
                else
                    r = "il ";
        return r + a;
    }
    
    public static void main(String[] args) {
        System.out.println(f("macchina", 2));
        System.out.println(f("zio", 0));
        System.out.println(f("libri", 1));
        System.out.println(f("ieri", 0));
        System.out.println(f("aquile", 3));
        System.out.println(f("spagnoli", 1));
        System.out.println(f("golf", 0));
        System.out.println(f("ombra", 2));
        System.out.println(f("impossibili", 1));
    }
}

Uses a little bit of regex magic and acts depending on the two booleans specified. To my surprise, no imports are needed, which helps out with the code size!

\$\endgroup\$
6
  • 1
    \$\begingroup\$ Mine is...longer than JAVA?! I must golf mine down a bit more asap! Good job though! +1 \$\endgroup\$
    – R. Kap
    Jul 16, 2016 at 5:32
  • \$\begingroup\$ If I had to take my arguments from the command line or stdin, believe me, it would have been a lot longer :P \$\endgroup\$
    – user55852
    Jul 16, 2016 at 5:37
  • \$\begingroup\$ Yes, Booleans accepted too. I've edited that in \$\endgroup\$
    – Luis Mendo
    Jul 16, 2016 at 8:26
  • \$\begingroup\$ I think you can use 0/1 instead of false/true which should save you some bytes. \$\endgroup\$
    – Leaky Nun
    Jul 16, 2016 at 11:17
  • \$\begingroup\$ Not using String e = "[^aeiou]).*"; actually saves you 5 bytes. \$\endgroup\$
    – Leaky Nun
    Jul 16, 2016 at 11:18
3
\$\begingroup\$

Ruby, 147 146 bytes

Try it online?

It might be possible to use a better method to determine which article to use, but I'm not aware of any.

As per the spec, the identifier is a number, as follows:

0: Masculine Singular
1: Masculine Plural
2: Feminine Singular
3: Feminine Plural

->w,i{(%w"lo gli la le l' gli l' le il i la le"[(0..2).find{|r|[/^(i[aeiou]|s[^aeiou]|z|x|[gp]n|ps)/,/^[aeiou]/,//][r]=~w}*4+i]+' '+w).sub"' ",?'}
\$\endgroup\$
2
\$\begingroup\$

Batch, 446 390 385 380 bytes

@echo off
set w=%2
call:l %1 l' gli_ l' le_ il_ i_ la_ le_ lo_ gli_ le_ le_
exit/b
:l
for /l %%a in (0,1,%1)do shift
set o=%5
for %%a in (gn pn ps)do if %%a==%w:~,2% set o=%9
for %%a in (s z x)do if %%a==%w:~,1% set o=%9
for %%a in (a e i o u)do if %%a==%w:~,1% set o=%1
for %%a in (a e i o u)do if i%%a==%w:~,2% (set o=%9)else if s%%a==%w:~,2% set o=%1
echo %o:_= %%w%

New version uses the same 0-3 encoding for the gender and number as several other answers. Works by creating a 1-dimensional array %2 .. %13 of forms, then shifting out the first 1+%1 elements so that the forms of interest become %1, %5 and %9 (which is fortunate as Batch won't go above %9 without shifting). It then laboriously checks the lists of prefixes to find out which form needs to be used. _ is used as a placeholder to represent a space until the word is output.

\$\endgroup\$
2
  • \$\begingroup\$ Might as well have them encoded into a single digit (or letter if needed, since the spec allows it) to save bytes. Everything is for the sake of the bytes! \$\endgroup\$
    – Value Ink
    Jul 16, 2016 at 1:32
  • \$\begingroup\$ @KevinLau-notKenny Switching to digit encoding allowed me to save a whopping 56 bytes by rewriting the gender and number handling! \$\endgroup\$
    – Neil
    Jul 16, 2016 at 18:37
1
\$\begingroup\$

Python 3, 235 bytes

I was interested to see how short I could get this in Python without regexes. It turns out that this is not the best option...

lambda s,c,v='aeiou':[["l'",'il','lo'],['gli','i','gli'],["l'",'la','la'],['le']*3][c][[[1,2][s[0]=='s'and s[1]not in v or s[0]in'zx'or s[:2]in['gn','pn','ps']or s[0]=='i'and s[1]in v],0][s[0]in v and not(s[0]=='i'and s[1]in v)]]+' '+s

An anonymous function that takes input via argument of the word s and the gender-number code c as an integer, using the following mapping:

0 - Masculine Singular
1 - Masculine Plural
2 - Feminine Singular
3 - Feminine Plural

and returns the word with the correct article.

How it works

A list containing the possibilities for each c as separate lists is created. The list is then indexed into using the value of c, yielding a 3-element list with the relevant options. A list index is now chosen by indexing into another nested list with the results of Boolean expressions. If the first character of s is a vowel and is not i followed by a vowel, the option for vowel is yielded via the returning of the index 0. Else, a Boolean expression returning True for cons. B and False for cons. A is evaluated, yielding the indices 2 and 1 respectively. Finally, the index is used to yield the article, which is concatenated with a space and the original string before being returned.

Try it on Ideone

\$\endgroup\$
1
\$\begingroup\$

JavaScript 210 bytes

(s,p)=>{var c=i=>!("aeiou".indexOf(s[i])+1),r=["z","gn","pn","ps","x"].some(t=>!s.indexOf(t))||(c(1)?s[0]=="s":s[0]=="i")?2:c(0)?1:0;return (p&1?(p&2?"le ":r&1?"i ":"gli "):!r?"l'":p&2?"la ":r&1?"il ":"lo ")+s}

An anonymous function taking two parameters s and p where

s  is the input string
p  is plurality (bit 0, set=plural) and gender (bit 1, set=f) combined as
    0 = masculine singular
    1 = masculine plural
    2 = feminine singular
    3 = feminine plural

After assigning the function to a variable and some unpacking), it can be tested as

var f=(s,p)=>{
    var c = i=>!("aeiou".indexOf(s[i])+1),
        r = ["z","gn","pn","ps","x"].some(t=>!s.indexOf(t))
             || ( c(1)? s[0]=="s":s[0]=="i" )
             ?   2 : c(0) ? 1 : 0;

     return (p&1?(p&2?"le ":r&1?"i ":"gli "):!r?"l'":p&2?"la ":r&1?"il ":"lo ")+s;
}

console.log("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
 f("macchina",2),
 f("zio",0),
 f("libri",1),
 f("ieri", 0),
 f("aquile",3),
 f("spagnoli",1),
 f("golf",0),
 f("ombra",2),
 f("impossibili",1))

where

  • c is a function to test s for a consonant at position i.
  • r evaluates to 0 for starting with a vowel, 1 for starting with a type A consonant and 2 for starting with a type B consonant (tested in reverse order).
  • Bit bashing in the return statement puts it together.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.