I programming puzzles, il code golf

21

2

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

Luis Mendo

Posted 2016-07-15T22:56:24.607

Reputation: 87 464

You may want to also make a challenge on the coniugation of regular verbs. – user6245072 – 2016-07-16T09:31:37.427

@user6245072 Well, there's already this... the difference would probably be too small

– Luis Mendo – 2016-07-16T09:49:17.537

1A 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. – Janus Bahs Jacquet – 2016-07-16T19:56:54.513

@JanusBahsJacquet Oh, I thought it was called semiconsonant also in English (as in Spanish) when it appears in the beginning of a syllable. I've corrected it. I had no idea about gli dei or per lo meno. Thanks for the information! – Luis Mendo – 2016-07-17T02:45:11.600

1As Italian I ask you to take off ieri test case because is an adverb and not a noun! (BTW it was formally correct) Please! – Giacomo Garabello – 2016-07-18T14:40:26.050

@GiacomoGarabello I know it's an adverb, but it's also used as a noun, isn't it?, as it is in English and in Spanish. Anyway, if you think it's too streched, can you suggest a noun that starts with semiconsonant "i-"?

– Luis Mendo – 2016-07-18T14:57:17.677

In 21 years of life in Italy I never seen Ieri used as a noun, but i know it's formally correct! In only sounds awful in my head... And then, It's a Code-Golf! If we don't need a clean code, we also don't need a clean language, if it works! – Giacomo Garabello – 2016-07-18T15:23:50.720

@GiacomoGarabello So can't you say something like "Non pensare allo ieri, pensa allo domani" (non-native here) – Luis Mendo – 2016-07-18T15:25:38.470

1We usally say: "Non pensare a ieri, Pensa a Domani" – Giacomo Garabello – 2016-07-18T15:27:30.957

@GiacomoGarabello Anyway, isn't ieri and domani nouns there? :-) – Luis Mendo – 2016-07-18T15:28:08.373

@GiacomoGarabello Thanks for the idea anyway. I think I'll leave "ieri" because quite a few answers are using it as a test case – Luis Mendo – 2016-07-18T15:38:35.767

Good Check! But in special cases like this one we don't use the Articles! We use the preposition. Before I've mispelled... I never seen Ieri used as a noun had to be I never seen Ieri used as a noun with a defined Article (My awful English didn't help me explaining italian grammar :-P ) I cant think about a phrase with lo Ieri in the Italian common language :-D – Giacomo Garabello – 2016-07-18T15:38:53.017

@GiacomoGarabello Got it. Thanks for the tip! E spero che possiamo parlare (scrivere) in italiano alcuna volta se visiterai lo chat :-) – Luis Mendo – 2016-07-18T15:42:39.210

Of course you can keep it, It's Correct! My only word about that it's uncommon and we don't use it that much (and it's sound is awful)! P.S.: Se vuoi Imparare l'italiano spero di poterti essere di aiuto! – Giacomo Garabello – 2016-07-18T15:43:41.940

Answers

7

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.

Leaky Nun

Posted 2016-07-15T22:56:24.607

Reputation: 45 011

4

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)

R. Kap

Posted 2016-07-15T22:56:24.607

Reputation: 4 730

zzz and yyy or xxx is two bytes shorter than [xxx,yyy][bool(zzz)] – Leaky Nun – 2016-07-16T14:16:30.010

@LeakyNun I can do that? Wow, I did not even know. Thanks! :) – R. Kap – 2016-07-16T18:13:23.140

It works as long as yyy is truthy. – Leaky Nun – 2016-07-16T18:18:09.983

@LeakyNun Yeah, of course. – R. Kap – 2016-07-16T18:31:23.867

["l'",'gli '][b%2] is 3 bytes shorter than ["l'",'gli ',"l'"][b] – Leaky Nun – 2016-07-16T18:47:08.447

@LeakyNun Wow, genius! I did not think of that! Thanks again! :) – R. Kap – 2016-07-16T18:49:11.887

I believe you can use and or to replace if else. – Leaky Nun – 2016-07-16T18:56:06.973

@LeakyNun Yeah, that is just what I was about to do. – R. Kap – 2016-07-16T18:56:31.687

@LeakyNun Actually, that is 2 bytes longer since I have use more parenthesis in that case. – R. Kap – 2016-07-16T19:03:18.890

4

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!

user55852

Posted 2016-07-15T22:56:24.607

Reputation:

1Mine is...longer than JAVA?! I must golf mine down a bit more asap! Good job though! +1 – R. Kap – 2016-07-16T05:32:08.727

If I had to take my arguments from the command line or stdin, believe me, it would have been a lot longer :P – None – 2016-07-16T05:37:16.583

Yes, Booleans accepted too. I've edited that in – Luis Mendo – 2016-07-16T08:26:46.810

I think you can use 0/1 instead of false/true which should save you some bytes. – Leaky Nun – 2016-07-16T11:17:19.693

Not using String e = "[^aeiou]).*"; actually saves you 5 bytes. – Leaky Nun – 2016-07-16T11:18:31.880

Your ungolfed code still has 3 ternary operators. – Leaky Nun – 2016-07-16T11:19:57.977

3

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"' ",?'}

Value Ink

Posted 2016-07-15T22:56:24.607

Reputation: 10 608

2

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.

Neil

Posted 2016-07-15T22:56:24.607

Reputation: 95 035

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! – Value Ink – 2016-07-16T01:32:08.420

@KevinLau-notKenny Switching to digit encoding allowed me to save a whopping 56 bytes by rewriting the gender and number handling! – Neil – 2016-07-16T18:37:57.917

1

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

TheBikingViking

Posted 2016-07-15T22:56:24.607

Reputation: 3 674

1

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.

traktor53

Posted 2016-07-15T22:56:24.607

Reputation: 299