Disclaimer: This isn't my challenge but ThisGuy said I was OK to post.
Occasionally I want to make a word into it's opposite, like happiness
goes to unhappiness
. Unfortunately when this happens, my brain will sometimes go blank. Then one day, after yet another this happening, I thought to my self "This is what programs are for!"
As the English language has many exceptions, I have created a list which contains the prefix for the starting letter
q or h -> dis- (honest -> dishonest)
l -> il- (legal -> illegal)
m or p -> im- (mature -> immature)
r -> ir- (responsible -> irresponsible)
everything else -> un- (worthy -> unworthy)
Task
Given an input as a string, make the string into its negative and output the result. You can assume that all the inputs given will fit the above rules. Submissions may be programs or functions, not snippets.
Input
A single string, taken either as a parameter or from STDIN
Output
The negated form of that string, conforming to the above rules
How to Win
This is a code-golf so shortest code wins
20 Answers 20
Python, 55 bytes
lambda n:'ddiiiiuiimmlrnss'[5-'rlmphq'.find(n[0])::7]+n
We need to handle 7 different starting letters:
g
-> dis
, h
-> dis
, p
-> im
, m
-> im
, l
-> il
, r
-> ir
and everything else -> un
We can store all these negations in a single string and extract the right one through slicing:
d i s
d i s
i m
i m
i l
i r
u n
'ddiiiiuiimmlrnss'[i::7]
Now we need to calculate the start index i
. 'rlmphq'.find
returns 0 for 'r'
, 5 for q
and -1 for everything not contained in the string.
To get the needed value from 0 to 6 we still need to subtract the return value from 5, resulting in this code:
'ddiiiiuiimmlrnss'[5-'rlmphq'.find(n[0])::7]
-
\$\begingroup\$ That's really cute! \$\endgroup\$Steve Bennett– Steve Bennett2017年04月06日 10:59:11 +00:00Commented Apr 6, 2017 at 10:59
-
\$\begingroup\$ Can someone explain how the hell is this works? I understand what's going on with the slice notation, but what are the magic strings
ddiiiiuiimmlrnss
andrlmphq
and the number5
for, why is the slice skip 7? \$\endgroup\$Keatinge– Keatinge2017年04月06日 19:51:36 +00:00Commented Apr 6, 2017 at 19:51 -
\$\begingroup\$ @Keatinge added an explanation. I hope it helps you \$\endgroup\$ovs– ovs2017年04月06日 20:52:07 +00:00Commented Apr 6, 2017 at 20:52
GNU sed, 50 bytes
Includes +1 for -r
s/^q|^h/dis&/
s/^l|^r|^m/i&&/
s/^p/imp/
t
s/^/un/
Nothing fancy. Uses &
in the replacement to combine a few substitutions, and t
to skip the last one if one of the first substitutions happens.
Jelly, 30 bytes
1ị"qmlrrhp"iị"3bμWI=ṡ÷ʠ$»œs5¤;
How?
1ị"qmlrrhp"iị"3bμWI=ṡ÷ʠ$»œs5¤; - Main link: string
1ị - 1 index into the string (first character of the string)
i - 1-based index of 1st occurrence of that in (else zero):
"qmlrrhp" - char list "qmlrrhp"
ị - index into (1-based and modulo):
¤ - nilad followed by link(s) as a nilad:
"3bμWI=ṡ÷ʠ$» - compressed string "dis"+"imili"+"run"="disimilirun"
œs5 - split "equally" into 5: ["dis","im","il","ir","un"]
; - concatenate with the string
Note that the repeated r
in "qmlrrhp"
is in the 5th index, which, if referenced, would result in prepending un
, so it could equally well be anything other than h
or p
.
TI-Basic, 104 bytes
Prompt Str0
sub(Str0,1,1→Str2
Str0
If Str2="Q" or Str2="H
"DIS"+Ans
If Str2="L
"IL"+Ans
If Str2="M" or Str2="P
"IM"+Ans
If Str2="R
"IR"+Ans
If Ans=Str0
"UN"+Ans
Ans
Requires all capital letters.
Explanation:
Prompt Str0 # 4 bytes, input user string to Str0
sub(Str0,1,1→Str2 # 12 bytes, store first character in Str2
Str0 # 3 bytes, store Str0 in Ans
If Str2="Q" or Str2="H # 14 bytes, if the first letter was Q or H
"DIS"+Ans # 8 bytes, store DIS+Ans in Ans
If Str2="L # 7 bytes, If the first letter was L
"IL"+Ans # 7 bytes, store IL+Ans in Ans
If Str2="Q" or Str2="H # 14 bytes, if the first letter was Q or H
"IM"+Ans # 7 bytes, store DIS+Ans in Ans
If Str2="R # 7 bytes, if the first letter was R
"IR"+Ans # 7 bytes, store IR+Ans in Ans
If Ans=Str0 # 6 bytes, if Ans has not been changed (first letter was none of the above)
"UN"+Ans # 7 bytes, store UN+Ans in Ans
Ans # 1 byte, implicitly return Ans
///, (削除) 59 (削除ここまで) 56 bytes
/^/\/\/#//#qu/disqu^h/dish^l/ill^m/imm^p/ipp^r/irr^/un/#
Input goes after the very last #
.
How it works:
I made an optimization that reduced the size to 56 bytes, but since that complicates things I will explain the original version, then explain the golf.
/#qu/disqu//#h/dish//#l/ill//#m/imm//#p/ipp//#r/irr//#/un/# |everything after the ` |` is not code.
/#qu/disqu/ |replace `qu` with `disqu`
/#h/dish/ |replace `h` with `dish`.
/#l/ill/ |replace `l` with `ill`.
/#m/imm/ |replace `m` with `imm`.
/#p/ipp/ |replace `p` with `ipp`.
/#r/irr/ |replace `r` with `irr`.
/#/un/ |replace everything else with `un`.
# |safety control
Intuition: The challenge is simple enough, just add the negative depending on the beginning of the word. However, in ///, you cannot just concatenate if [...]
, you can only replace something following a specific pattern. So in this program, the positive word beginnings are replaced with the negative word beginnings. The #
was added to make sure that once a new beginning was added, no more new beginnings would be added. The #
also made it possible to do 'everything else: un'.
The golf incorporates a new substitution at he beginning: /^/\/\/#/
. This replaces all ^
with //#
, which was a common pattern in the original version.
Batch, 114 bytes
@set/pw=
@set p=un
@for %%p in (dis.q dis.h il.l im.m im.p ir.r)do @if .%w:~,1%==%%~xp set p=%%~np
@echo %p%%w%
Checks the first character of the word against the list of custom prefixes and if so changes the prefix from the default of un
. Special-casing qu
is possible at a cost of 21 bytes.
Javascript, (削除) 72 (削除ここまで) (削除) 71 (削除ここまで) (削除) 66 (削除ここまで) (削除) 61 (削除ここまで) (削除) 60 (削除ここまで) 59 bytes
(削除) w=>('dis....il.im...im.dis.ir'.split('.')[w.charCodeAt(0)-104]||'un')+w
(削除ここまで)
(削除) w=>'un.dis.dis.il.im.im.ir'.split('.')['qhlmpr'.indexOf(w[0])+1]+w
(削除ここまで)
(削除) Yeah, it's still longer than an existing solution. :) (削除ここまで)
w=>['un','dis','im','il','ir']['qmlrhp'.search(w[0])%4+1]+w
In case this needs any explanation, I'm taking advantage of the q/h and m/p pairs by combining their index in the search string with a mod 4, then using that as the lookup into the prefix array.
-
\$\begingroup\$ Great answer. Save 1 byte using
search
instead ofindexOf
. And some more, I think, using&
instead of%
\$\endgroup\$edc65– edc652017年04月06日 10:53:48 +00:00Commented Apr 6, 2017 at 10:53 -
\$\begingroup\$ Thank you! I didn't know about
search
. Can't see how to make the & trick work - would be perfect if my array was only 4 elements. \$\endgroup\$Steve Bennett– Steve Bennett2017年04月06日 11:07:39 +00:00Commented Apr 6, 2017 at 11:07
JavaScript ((削除) 71 (削除ここまで) (削除) 64 (削除ここまで) 61 bytes)
w=>({q:a='dis',h:a,l:'il',m:b='im',p:b,r:'ir'}[w[0]]||'un')+w
Edits:
- Saved 7 bytes thanks to @ErtySeidohl (
charAt(0)
->[0]
) - Saved 3 bytes thanks to @edc65 (assigning shared prefixes to variables)
var f = w=>({q:a='dis',h:a,l:'il',m:b='im',p:b,r:'ir'}[w[0]]||'un')+w;
function onChange() {
var word = event.target.value;
var output = f(word);
document.getElementById('output').innerHTML = output;
}
Input Word: <input type='text' oninput='onChange()'/><br/>
Output Word: <span id="output">
-
1\$\begingroup\$ If you don't care about backward compatibility with IE7, couldn't you use
w[0]
instead ofw.charAt(0)
? \$\endgroup\$Erty Seidohl– Erty Seidohl2017年04月06日 02:21:18 +00:00Commented Apr 6, 2017 at 2:21 -
\$\begingroup\$ @ErtySeidohl Thanks! Just learned something new ;-) \$\endgroup\$forrert– forrert2017年04月06日 04:41:27 +00:00Commented Apr 6, 2017 at 4:41
-
\$\begingroup\$ I'm new here, but is it legitimate to provide an answer starting with just
w=>...
? The actual function definition would includelet f=w=>...
? (Probably covered in an FAQ somewhere...) \$\endgroup\$Steve Bennett– Steve Bennett2017年04月06日 07:10:53 +00:00Commented Apr 6, 2017 at 7:10 -
\$\begingroup\$ @SteveBennett yes it's legitimate. Naming the function is not relevant \$\endgroup\$edc65– edc652017年04月06日 10:32:08 +00:00Commented Apr 6, 2017 at 10:32
-
1\$\begingroup\$
w=>({q:a='dis',h:a,l:'il',m:b='im',p:b,r:'ir'}[w[0]]||'un')+w
3 bytes less \$\endgroup\$edc65– edc652017年04月06日 10:52:47 +00:00Commented Apr 6, 2017 at 10:52
Haskell, 71 bytes
f l=maybe"un"id(lookup(l!!0)$zip"qhlmpr"$words"dis dis il im im ir")++l
Usage example: f "legal"
-> "illegal"
. Try it online!
Build a lookup table of prefix/replacement pairs for looking up the first char of the input string with a default value of "un"
if not found.
Mathematica, 107 bytes
StringReplace[StartOfString~~x:#:>#2<>x&@@@{{"q"|"h","dis"},{"l","il"},{"m"|"p","im"},{"r","ir"},{_,"un"}}]
Explanation:
StartOfString~~x:#:>#2<>x&
is a pure function where the first argument is a string pattern to match at the beginning of the string and the second argument is a string to prepend to the match. It returns a delayed rule suitable for use within StringReplace
. This is then applied to each of the pairs {{"q"|"h","dis"},{"l","il"},{"m"|"p","im"},{"r","ir"},{_,"un"}}
resulting in the list of rules
{
StartOfString~~x:"q"|"h":>"dis"<>x,
StartOfString~~x:"l":>"il"<>x,
StartOfString~~x:"m"|"p":>"im"<>x,
StartOfString~~x:"r":>"ir"<>x,
StartOfString~~x_:>"un"<>x
}
Finally this list is passed into StringReplace
which gives an operator on strings.
-
2\$\begingroup\$ Does Mathmatica have a builtin for everything? \$\endgroup\$user67719– user677192017年04月05日 21:14:18 +00:00Commented Apr 5, 2017 at 21:14
Retina, 54 bytes
^[^hqlmpr]
un$+
^[hq]
dis$+
^l
il$+
^[mp]
im$+
^r
ir$+
Explanation:
{implicit replace stage}
^[^hqlmpr] Append un to words starting with none of: hqlmpr
un$+
^[hq] Append dis to words starting with h or q
dis$+
^l Append il to words starting with l
il$+
^[mp] Append il to words starting with m or p
im$+
^r Append ir to words starting with r
ir$+
First time I've used Retina. It's a pretty neat language.
-
\$\begingroup\$ Very nice first try at a language! +1 \$\endgroup\$Arjun– Arjun2017年04月06日 08:22:23 +00:00Commented Apr 6, 2017 at 8:22
-
\$\begingroup\$ And with that you have 2500 rep! Congratulations! \$\endgroup\$Arjun– Arjun2017年04月06日 08:23:02 +00:00Commented Apr 6, 2017 at 8:23
-
\$\begingroup\$ And your user index is 26600! \$\endgroup\$Arjun– Arjun2017年04月06日 08:23:38 +00:00Commented Apr 6, 2017 at 8:23
-
\$\begingroup\$ So much perfect base-10 ! \$\endgroup\$Arjun– Arjun2017年04月06日 08:24:13 +00:00Commented Apr 6, 2017 at 8:24
C, (削除) 109 (削除ここまで) 107 bytes
f(char*s){printf("%s%s",*s-109&&*s-112?*s-108?*s-114?*s-104&&*s-113|s[1]-117?"un":"dis":"ir":"il":"im",s);}
PHP, 101 Bytes
echo preg_match("#^(qu|[hlmpr])#",$argn,$t)?[qu=>dis,h=>dis,l=>il,m=>im,p=>im,r=>ir][$t[1]]:un,$argn;
Excel 78 bytes
=TRIM(MID(" disdisil im im ir un",IFERROR(FIND(LEFT(A1),"qhlmpr"),7)*3,3))&A1
I found some close contenders using different methods that scored 81 bytes:
=IFERROR(CHOOSE(FIND(LEFT(A1),"qhlmpr"),"dis","dis","il","im","im","ir"),"un")&A1
And 84 bytes:
=IFERROR(TRIM(MID("im disi"&LEFT(A1),MOD(FIND(LEFT(F1),"qlmhrp"),3)*3+1,3)),"un")&A1
REXX, 78 bytes
arg a
s.=un
s.q=dis
s.h=s.q
s.l=il
s.m=im
s.p=im
s.r=ir
p=left(a,1)
say s.p||a
Saves a few bytes by replying in UPPERCASE, e.g. potent -> IMPOTENT.
Perl, 49 + 1 (-p
flag) = 50 bytes
s|^[hq]|dis$&|||s|^[lmr]|i$&$&|||s|p|imp|||s||un|
Using:
perl -pe 's|^[hq]|dis$&|||s|^[lmr]|i$&$&|||s|p|imp|||s||un|' <<< responsible
Clojure, 65 bytes
#(str(get{\q"dis"\h"dis"\l"il"\m"im"\p"im"\r"ir"}(first %)"un")%)
Well this is boring... but I couldn't make it any shorter. At least there is very little whitespace.
OCaml, 85
(fun s->(match s.[0]with|'q'|'h'->"dis"|'l'->"il"|'m'|'p'->"im"|'r'->"ir"|_->"un")^s)
Anonymous function, uses pattern matching on its first char.
PowerShell, (削除) 66 (削除ここまで) 62 bytes
%4+1
inspired by @Steve Bennett
param($s)(echo un dis im il ir)[('qmlrhp'|% I*f $s[0])%4+1]+$s
q
without au
? \$\endgroup\$qadi
,qat
, the aforementionedqi
,qirsh
, andqwerty
. (I play a lot of Scrabble) \$\endgroup\$q
is always followed by au
in the string or not? \$\endgroup\$u
\$\endgroup\$