# Is it a noun or not?

Given a string as input, determine whether it is a noun or not.

You will be scored on the 1000 most common English words, by how many you correctly label as a noun or not.

The program or function which correctly classifies the most of those words in 50 bytes or less will win.

# Nouns

A noun is a word that represents a thing, typically. It gets more complex, but that's the basic idea.

In cases where a word could either be a noun or some other part of speech, I classified it as a noun, even if that's a rare usage. Or actually, I let this site do it for me.

The words you'll be scored on are these 1000 common words, which are from simple Wikipedia, with "two" and "once" added. Of those, these are the 586 nouns, and these are the 414 non-nouns. You can find all three lists here. Note that all of these inputs are in lower case. These lists are final - don't try to argue grammar.

Your program will be considered correct if it outputs a truthy result on an input which is a noun, and a falsy result on an input which is not a noun.

Subtleties:

Programs must have a deterministic output. If you want to use randomness, seed it. Programs are not allowed to use built-in noun lists or other built-in part-of-speech functionality.

Examples:

a: noun
act: noun
active: noun
above: non-noun
across: non-noun


Please indicate what your program's success rate is in your answer. The program or function of at most 50 bytes with the highest success rate wins. In case of a tie, lowest byte count will determine a winner. Good luck!

## JavaScript (ES6), 43 bytes, 622630 633

Just to get the ball rolling. Returns 1 for nouns, 0 for non-nouns.

s=>2552>>s.length&/^[bcdf-mp-tvwy]/.test(s)


### How?

We bet on noun if both following conditions are met:

1. The word length is 3, 4, 5, 6, 7, 8 or 11. This is done by right-shifting the binary number 100111111000 (2552 as decimal).
2. The word starts with one of these letters: bcdfghijklmpqrstvwy
• Just as I was about to comment, with JS specifically in mind, that the byte limit was far too restrictive, you post this! I was thinking, without having looked at the list, that a better score than 586 might just be possible by testing the first letter or 2 in each word. Nicely done :) – Shaggy Aug 12 '17 at 21:39
• An explanation would be nice, for people less familiar with Javascript. As far as I can tell, this checks whether the word length is 3, 4, 5, 6, 7, 8 or 11, and the word also starts with one of a set of letters? – isaacg Aug 12 '17 at 22:01
• @isaacg That's correct. Explanation added. – Arnauld Aug 12 '17 at 22:14
• Note that the character class [bcdf-mp-tvwy] is equivalent to the class [^aenouxz]. A change would save 4 bytes, which could be capitalized on. – fireflame241 Aug 12 '17 at 22:14
• @fireflame241 Very true. And that can even be shortened to [^aenouz] because we don't have any word starting with a x. – Arnauld Aug 12 '17 at 22:19

# Jelly, 48 bytes, score 731

This is my first ever answer in Jelly and I went to a lot of trouble putting this together. Ah well ... that was fun. :-)

O‘ḅ⁹%⁽€Oæ»4“Ạ$ⱮẊḲḲLÑMṆụ⁻ẉṂŻvḤæɠ5ṭȯƁU*×TdƲḥ’æ»Ḃ  1 byte saved thanks to @JonathanAllan Try it online! ### Breakdown and test suites • Non-nouns correctly identified as non-nouns: 265 / 414 (64%) • Nouns correctly identified as nouns: 466 / 586 (79.5%) ### How? We first compute a hash of the input string by: • converting it to an integer by interpreting each code point as a base-256 digit • applying modulo 4080 (chosen as the most efficient value with no more than 12 bits) • keeping the 8 most significant bits of the result This leaves us with an index in [0 ... 255] and thus divides all words into 256 groups. For each group of words, we pre-compute a binary flag which is 1 if the group contains more nouns than non-nouns, and 0 otherwise. This leads to a 256-bit number N that we're going to use as a lookup-table. We store it as a base-250 encoded string. Below is the binary representation of N. 1000011000001011000101111011111001001101110010101101110010001101 0000010001101010010111110001110010010101110110110010111111010000 0001111010011110000110101011111000011110111011010011011110101100 1010010110101111000010101000101100000001110110100011111000101010  Which can be stored as “Ạ$ⱮẊḲḲLÑMṆụ⁻ẉṂŻvḤæɠ5ṭȯƁU*×TdƲḥ’ in Jelly.

Hence the code:

O‘ḅ⁹%⁽€Oæ»4“Ạ$ⱮẊḲḲLÑMṆụ⁻ẉṂŻvḤæɠ5ṭȯƁU*×TdƲḥ’æ»Ḃ main link O convert the input string to a list of code points ‘ increment each of them ḅ⁹ convert from base 256 to an integer %⁽€O modulo 4080 æ»4 drop the 4 least significant bits “Ạ$ⱮẊḲḲLÑMṆụ⁻ẉṂŻvḤæɠ5ṭȯƁU*×TdƲḥ’æ»     right shift N by this amount
Ḃ    test the least significant bit

• Nice job! Save a byte to boot with O‘ḅ⁹%⁽€Oæ»4“Ạ$ⱮẊḲḲLÑMṆụ⁻ẉṂŻvḤæɠ5ṭȯƁU*×TdƲḥ’æ»Ḃ (also note you can use the footer on TIO, I'd go with Ç€¬S,L and Ç€S,L for your two test suites. – Jonathan Allan Aug 14 '17 at 20:38 • @JonathanAllan Thanks for the tips! – Arnauld Aug 14 '17 at 21:16 # JavaScript (ES6), 50 bytes, score 693 s=>!/^([aouz]|th|..$)|e.+[ey]|[flo].r|a.p/.test(s)


Just looking for any possible patterns that non-nouns have that nouns don't.

Non-nouns more often contain:

1. a, o, u, or z as the first letter.
2. th as the first two letters.
3. Two letters only. [Think pronouns (me, we, us, he, it) and prepositions (of, to, in, on, by, at, up, ...).]
4. e, followed by one or more letters, followed by e or y.
5. f, l, or o, followed by any letter, followed by r.
6. a, followed by any letter, followed by p.

Snippet:

var nouns = ['a','act','active','activity','age','air','amount','answer','anything','apple','area','arm','army','art','ask','attack',
'cake','call','can','candle','cap','car','card','care','carry','case','cat','catch','chair','chance','change','chicken','child','chocolate','choice','city','class','clock','clothes','cloud','coffee','coat','cold','comfortable','common','computer','condition','control','cook','corner','cost','count','country','course','cover','crash','cross','cry','cup','cut',
'ear','earth','east','eat','education','effect','egg','end','equal','entrance','escape','evening','event','examination','example','exercise','eye',
'face','fact','fail','fall','family','farm','father','fat','fault','fear','feed','feel','female','few','fight','fill','film','finger','finish','fire','fish','fix','floor','flower','fly','fold','food','foot','football','force','form','freedom','friend','front','fruit','fun','funny','future',
'ice','idea','if','increase','inside','iron','invite','island','it',
'job','join','juice','jump',
'keep','key','kill','kind','king','kitchen','knee','knife',
'machine','main','make','male','man','many','map','mark','market','matter','meal','meat','medicine','meet','member','mention','method','middle','milk','mind','minute','miss','mistake','mix','model','moment','money','month','morning','most','mother','mountain','mouth','move','music',
'name','nation','nature','neck','net','news','newspaper','night','noise','north','nose','nothing','notice','number',
'object','offer','office','oil','one','opposite','orange','order','other','outside','page','pain','paint','pair','paper','parent','park','part','partner','party','pass','past','path','pay','peace','pen','people','period','person','piano','pick','picture','piece','pin','place','plane','plant','plastic','plate','play','plenty','point','police','pool','position','possible','potato','power','present','press','price','private','prize','problem','produce','promise','public','pull','push','put',
'queen','question','quiet',
'table','talk','taste','tea','teach','team','tear','telephone','television','tell','tennis','test','thing','tie','title','today','toe','tomorrow','tonight','tool','tooth','top','total','touch','town','train','travel','tree','trouble','trust','try','turn','type',
'uncle','unit','use','usual',
'vegetable','village','voice','visit',
'wait','wake','walk','wash','watch','water','way','wear','weather','wedding','week','weight','welcome','west','wheel','while','white','wife','will','win','wind','window','wine','winter','wish','woman','wonder','word','work','world','worry',
'yard','yesterday','you','young',
'two'],
'be','bean','behave','before','begin','behind','below','besides','best','better','between','bleed','boil','born','borrow','both','breathe','bright','bring','build','busy','but','by',
'careful','careless','central','century','certain','chase','cheap','cheese','children','choose','circle','clever','clean','clear','climb','cloth','cloudy','close','coin','collect','colour','comb','compare','come','complete','continue','cool','copper','corn','correct','contain','cupboard',
'dangerous','decide','decrease','deer','depend','destroy','develop','die','different','difficult','dirty','discover','do','down','dry','duck',
'each','early','earn','easy','eight','either','electric','elephant','else','empty','enemy','enjoy','enough','enter','even','ever','every','everyone','exact','everybody','except','excited','expect','expensive','explain','extremely',
'false','famous','far','fast','fever','find','fine','first','fit','five','flag','flat','float','flour','fool','for','foreign','forest','forget','forgive','fork','fox','four','free','freeze','fresh','friendly','from','full','furniture','further',
'gentleman','get','goat','goodbye','grave','gray','grow','gun',
'hammer','happen','happy','hard','have','he','healthy','hear','heaven','hen','her','here','hers','hill','him','his','hobby','hot','how','hundred','hungry',
'i','important','in','into','introduce','invent','is','its',
'jelly','just',
'knock','know',
'lamp','large','last','late','lately','lazy','leaf','learn','left','lend','less','like','lion','little','live','lonely','lose','lot','lower',
'marry','may','me','mean','measure','million','modern','monkey','moon','more','much','must','my',
'narrow','near','nearly','need','needle','neighbour','neither','never','new','next','nice','nine','no','noble','none','nor','not','now',
'obey','ocean','of','off','often','old','on','only','open','or','our','out','over','own',
'quick','quite',
'take','tall','taxi','ten','terrible','than','that','the','their','then','there','therefore','these','thick','thin','think','third','this','though','threat','three','tidy','to','together','too','tram','true','twice',
'ugly','under','understand','until','up','useful','usually',
'very',
'want','warm','was','waste','we','weak','were','well','wet','what','when','where','which','who','why','wide','wild','wire','wise','with','without',
'yell','yet','your',
'zero','zoo',
'once'];

f=
s=>!/^([aouz]|th|..$)|e.+[ey]|[flo].r|a.p/.test(s) //truthy: tnoun = 0; nouns.forEach(s=>tnoun += f(s)); console.log('Nouns: ' + tnoun + ' correct'); //falsy: tnonNoun = 0; nonNouns.forEach(s=>tnonNoun += !f(s)); console.log('Non-nouns: ' + tnonNoun + ' correct'); console.log('Total: ' + (tnoun + tnonNoun) + ' correct'); • I believe you can save a byte by changing the first regex to /h|n/ (or by doing /^.[hn]/.test(s)), and another by changing s[2]>'' to either !!s[2] or 2 in s. – ETHproductions Aug 13 '17 at 2:47 • Thanks, @ETHproductions. I can use your suggestions and combine the two tests to save a bunch of bytes, which allowed me to add code to improve my score. – Rick Hitchcock Aug 13 '17 at 4:04 • Isn't a.p redundant since you already have [aouz]? – AdmBorkBork Aug 14 '17 at 13:31 • @AdmBorkBork, the a in [aouz] is matched only when at the beginning of the string. For whatever reason, testing for a.p anywhere in the string improves the score. – Rick Hitchcock Aug 14 '17 at 13:53 # Jelly, 50 bytes, score 763 Using a hash now (much like Arnauld's Jelly answer) OP%⁽Wpị“!ḋGẠ⁻Ṭȥʋt|Ḥ\⁾°½İ@G2ḂƑ½ịʂ¶ɦḲ⁷³Hz~⁵p9)⁹ƙ¿’B¤  Try It Online! 250 / 414 for Non-Nouns 513 / 586 for Nouns Total = 250 + 513 = 763. ### How? Builds a table with 308 entries, either 1 (identifying a noun) or 0 (identifying a non noun) and indexes into it using a key provided by a hash function that utilises the product of the ordinals of the input word: OP%⁽Wpị“!ḋGẠ⁻Ṭȥʋt|Ḥ\⁾°½İ@G2ḂƑ½ịʂ¶ɦḲ⁷³Hz~⁵p9)⁹ƙ¿’B¤ - Link: list of characters, word O - convert to ordinals P - product ⁽Wp - base 250 number = 22863 % - modulo (by 22863) ¤ - nilad plus link(s) as a nilad: “!ḋGẠ⁻Ṭȥʋt|Ḥ\⁾°½İ@G2ḂƑ½ịʂ¶ɦḲ⁷³Hz~⁵p9)⁹ƙ¿’ - base 250 number B - as a binary list (308 bits) ị - index into (1-indexed and modular, - so adds another modulo by 308)  ### Previous: 50 47 bytes, score 684 ḣ3Ẇf“QṘ°ḂżÐŒ#ḍæ09»s2¤Ȧ¬ȧØY⁾niyṖf⁽ż2ị$
0,-2ịE¬ȧÇ


A monadic link taking a word and returning a list of one character (truthy) if the word is identified as a noun, or an empty list or zero (both falsey) if it is not.

Try it online! (the footer performs an if else on the result to print Noun or Non-Noun)
...or see the scoring program (counts up truthy indexes across the two lists and then calculates the score).

Score breakdown: 462 / 586 nouns correctly identified (124 incorrect), 222 / 414 non-nouns correctly identified (192 incorrect) -- total correct = 684 / 1000.

### How?

Guess it is not a noun if...

• the last character and the character two before that are equal (with modular and 1-based indexing)
• either of the first two length 2 substrings are in:
'be', 'th', 'le', 'he', 'm ', 'ev', 'et', 's ', 'fl', 'ax', 'en', 'fo', 'am', 'az' (note: 'm ' and 's ' are only here to ease compression, but they never appear anyway)
• The -299th index (with modular and 1-based indexing) is any of:
aenouyz (although this is implemented inversely and with excess capital letters)
...since the words all have length between 1 and 11 the -299th index is equivalent to using the length to index mapping: {7:2; 8:5; 9:7; 11:9; else 1}

ḣ3Ẇf“QṘ°ḂżÐŒ#ḍæ09»s2¤Ȧ¬ȧØY⁾niyṖf⁽ż2ị$- Link 1: list of characters, word ḣ3 - head to index 3 (1st 3 characters, like 'abc') Ẇ - all sublists (['a','b','c','ab','bc','abc'] ¤ - nilad followed by link(s) as a nilad: “QṘ°ḂżÐŒ#ḍæ09» - compression of "bethlehem evets flaxenfoamaz" s2 - split into chunks of 2: - be,th,le,he,m ,ev,et,s ,fl,ax,en,fo,am,az f - filter keep (can only match 'ab' or 'bc') Ȧ - any and all (0 if empty, 1 if not) ¬ - logical not ØY - consonant -y yield = "BCD...WXZbcd...wxz" ⁾ni - character pair = "ni" (no shrubbery for you!) y - translate (exchange the n for an i) Ṗ - pop (remove the z) ȧ - logical and$ - last two links as a monad:
⁽ż2   -   base 250 literal = -299
ị  -   index into the word
f      - filter keep

0,-2ịE¬ȧÇ - Main link: list of characters, word
0,-2      - pair zero with -2 = [0,-2]
ị     - index into the word (last character and the one before the one before that)
E    - all (both) equal?
¬   - logical not
ȧ  - logical and


13 bytes, score: 638

A first quick bash (extended above)

ØY⁾niyṖf⁽ż2ị\$

• 0,-2 doesn't mean pair zero with -2 it means literal [0, -2] – Erik the Outgolfer Aug 13 '17 at 10:47
• But it's the very same effect :p – Jonathan Allan Aug 13 '17 at 10:48
• no it's not 0,-2 is a nilad, not separate (0)(,)(-2)...of course it's the same effect in this case but not always. I learned that the hard way...and whatever the case I'd anyways prefer to explain what actually happens instead of something with the same effect or something. – Erik the Outgolfer Aug 13 '17 at 10:49
• If I'd written "join" rather than "pair" would you have commented "no join is j"? – Jonathan Allan Aug 13 '17 at 10:56
• I might be a little bit pedantic, but pair or join are obviously wrong ways to phrase it, since 0,-2,-6 for example doesn't mean pair 0 with -2 and then pair that with -6 = [[0, -2], -6] but it rather means literal [0, -2, -6]. I get it, the , atom and the ...,...(,...(...)) literal are confusing...but stilll 0,-2,-6 isn't quite the same as 0,-2;-6 since the former is 1 link and the latter is 3 links. – Erik the Outgolfer Aug 13 '17 at 10:59

# Julia 34bytes, 609

f(w)=hash(w)&0x0800000000004808>0

I wanted to save on characters by using the in-built hash. I feel like there must be a way to do this better. Julia is just not friendly enough with the bit-banging operations I want to use to make this better I think.

Finding suitable bitmasks for the hash to separate them, is an interesting game.

• Best solution ;) – tamasgal Aug 15 '17 at 18:58

# Python 2, 50 bytes, accuracy: 596

lambda x:2<len(x)<7 or x[0]in"abcgmprs"or"st" in x


Try it online!

Simply checks first letter, length, and whether "st" is in the word Code assumes that word is defined as x (Edit: Thanks to issacg for fixing code from snippet to function)

• Hi, welcome to the site. While this is interesting, submissions are required to either be fuctions or full programs. This is a snippet, which is not allowed. See this Try it online! link for a way to convert this snippet to a function while still executing the same code. – isaacg Aug 17 '17 at 20:31

## Haskell, 36 bytes, 626 631

f x=length x>2&&x!!0notElem"aenou"

• 643 if anyone has a shorter language: length x>2&&(x!!0notElem"aenou"||x!!1elem"acqrsty") – BlackCap Aug 18 '17 at 14:15

# 2-level logic gate implementation, not 50 bytes, score 1000

1. Just plug the binary representation of the given word to the 88 inputs

1. complete the input word by spaces at right if the length of the word is less than 11
2. 8-bits ASCII code for each letter of the input word
2. The circuit returns 1 if the word is a noun, and returns 0 if not

3. The blue dashed lines are for never used inputs

This implementation needs

1. 48 transistors to encode all inverters gates
2. 1100 transistors to encode all AND gates
3. 154 transistors to encode the OR gate
4. Total of 1302 transistors which represents less than 28 bytes.

Some measurements

1. An inverter gate needs 1 transistor
2. A 2-inputs simple OR gate needs 2 transistors
3. A 2-inputs simple AND gate needs 2 transistors
4. One bit need 6 transistors

Full resolution Circuit.pdf here

Full resolution Circuit.png here

• Could you please explain exactly what your system for encoding this circuit into bytes is? I'm very confused how you claim to use 28 * 8 / 1302 = 0.17 bits per transistor. – isaacg Aug 16 '17 at 3:55
• As my solution is a very low level computer solution (hardware rather than software) I based my byte counting on transistors. Fro hardware point of view, a BIT is encoded by 6 transistors, so we can assume that one transistor represents 1/6 bit (around 0.17). – mdahmoune Aug 16 '17 at 17:23
• I understand your point of view, however the 50 bytes code source needs to exist somewhere on a concrete hardware (transistors generally) – mdahmoune Aug 16 '17 at 18:20
• It's not just a point of view - it's a requirement of the challenge. Please mark your answer as non-competing, as it does not meet the requirements to compete on this challenge. – isaacg Aug 17 '17 at 0:43
• A simple, uncompressed binary encoding of the information required to recreate this solution could use 2 bits for the type of each logic gate (3 different gates) and 10 bits for each address of each logic gate's input(s) and output (675 gates plus inputs and output). 2 * (48 + 550 + 77) + 10 * (2 * 48 + 3 * (550 + 77)) = 21120 bits = 2640 bytes. – Nnnes Aug 18 '17 at 14:38

# Python 3, 50 bytes, score 602

Python isn't the most verbose language, but 50 bytes is tough.

lambda x:all(x.count(y)<1for y in["ful","y","er"])