-6
\$\begingroup\$

Guidelines

Task

Given a DNA strand, return its RNA complement (per RNA transcription).

Both DNA and RNA strands are a sequence of nucleotides.

The four nucleotides found in DNA are adenine (A), cytosine (C), guanine (G) and thymine (T).

The four nucleotides found in RNA are adenine (A), cytosine (C), guanine (G) and uracil (U).

Given a DNA strand, its transcribed RNA strand is formed by replacing each nucleotide with its complement:

  • G -> C
  • C -> G
  • T -> A
  • A -> U

Rules

  • The input will always be either a string or an array/list of characters
  • The output should always be either a string or an array/list of characters
  • In the case of invalid input, you should output 'Invalid Input' as a string or an array/list of characters
  • You can assume that you will only be given printable ASCII characters.
  • This is code golf so the person with the least amount of bytes winsx

Examples

'C' -> 'G'

'A' -> 'U'

'ACGTGGTCTTAA' -> 'UGCACCAGAAUU'

'XXX' -> 'Invalid Input'

'ACGTXXXCTTAA' -> 'Invalid Input'


Other info

This task was taken from Exercism, which was founded by Katrina Owen and is licensed under the MIT License.

\$\endgroup\$
  • 19
    \$\begingroup\$ Boo-urns to input validation! \$\endgroup\$ – Shaggy Feb 18 '18 at 9:54
  • 19
    \$\begingroup\$ Here is a meta post explaining why input validation is usually discouraged. In this particular case, it also prevents the use of arithmetic solutions. \$\endgroup\$ – Arnauld Feb 18 '18 at 11:57
  • 1
    \$\begingroup\$ I remember seeing a sandboxed challenge like this that says "deleted too simple and probably dupe of many other things" something like that. \$\endgroup\$ – user202729 Feb 18 '18 at 15:21
  • 3
    \$\begingroup\$ (Recommend sandbox) \$\endgroup\$ – user202729 Feb 18 '18 at 15:22
  • 1
    \$\begingroup\$ Side note: https://exercism.io/ does not work for me. It's working fine without SSL, though. \$\endgroup\$ – Arnauld Feb 18 '18 at 15:59

18 Answers 18

2
\$\begingroup\$

05AB1E, 23 bytes

„—ÄGu©ÃQi®"GUAC"‡ë”ͼî®

Try it online!

Explanation

„—ÄGu©                    # push "CATG" and store a copy in register
      Ã                   # keep only those letters of input
       Qi                 # if the result equals the input
         ®"GUAC"‡         # translate "CATG" to "GUAC"
                 ë”Í¼î®   # else, push "Invalid Input"
\$\endgroup\$
  • 2
    \$\begingroup\$ Moar guacamole pls \$\endgroup\$ – Magic Octopus Urn Feb 19 '18 at 2:11
2
\$\begingroup\$

Python 3, 82 79 bytes

thanks to Laikoni for -3 bytes

lambda s:{*s}-{*'ACGT'}and'Invalid Input'or"".join("UCG A"[ord(c)%5]for c in s)

Try it online!

\$\endgroup\$
  • \$\begingroup\$ 79 bytes with "".join("UCG A"[ord(c)%5]for c in s): Try it online! \$\endgroup\$ – Laikoni Feb 19 '18 at 20:48
2
\$\begingroup\$

Coconut, 75 70 bytes

s->set(s)-set('ACGT')and'Invalid Input'or["UCG A"[ord(c)%5]for c in s]

Try it online! A mix of ovs' Python answer and my Haskell answer.

Edit: -5 bytes thanks to ovs!

\$\endgroup\$
  • \$\begingroup\$ This is shorter with a list comprehension. But I think returning a map object would be valid as well and is another byte shorter. \$\endgroup\$ – ovs Feb 22 '18 at 19:54
  • \$\begingroup\$ @ovs Thanks! Is there any consensus on map objects? \$\endgroup\$ – Laikoni Feb 22 '18 at 23:54
  • \$\begingroup\$ There is no specific consensus regarding iterators, but it is allowed to write a generator function. This is quite similar as the return value of a generator function is an generator, which is a specific type of an iterator just like a map object. \$\endgroup\$ – ovs Feb 23 '18 at 5:53
1
\$\begingroup\$

K (oK) / K4, 38 bytes

Solution:

(x;"Invalid Input")@|/^x:"CGAU""GCTA"?

Try it online!

Examples:

q)k)(x;"Invalid Input")@|/^x:"CGAU""GCTA"?"C"
"G"
q)k)(x;"Invalid Input")@|/^x:"CGAU""GCTA"?"C"
"G"
q)k)(x;"Invalid Input")@|/^x:"CGAU""GCTA"?"G"
"C"
q)k)(x;"Invalid Input")@|/^x:"CGAU""GCTA"?"ACGTGGTCTTAA"
"UGCACCAGAAUU"
q)k)(x;"Invalid Input")@|/^x:"CGAU""GCTA"?"XXX"
"Invalid Input"
q)k)(x;"Invalid Input")@|/^x:"CGAU""GCTA"?"ACGTXXXCTTAA"
"Invalid Input"

Explanation:

The mapping is trivial. 25 bytes for the "Invalid Input" portion.

(x;"Invalid Input")@|/^x:"CGAU""GCTA"? / the solution
                               "GCTA"? / return index in left list
                         "CGAU"        / index into this list
                       x:              / save as x
                      ^                / null, any nulls in x?
                    |/                 / take max
                   @                   / index into
( ;               )                    / two item list
   "Invalid Input"                     / result if null found
 x                                     / result if no nulls found
\$\endgroup\$
1
\$\begingroup\$

Retina, 36 31 bytes

T`GCTAp`CGAUx
K'x`Invalid input

Try it online!

Explanation

T`GCTAp`CGAUx

Perform the required character substitutions as a transliteration, while also replacing all invalid characters with x.

K'x`Invalid input

If the result contains x (i.e. the input contained an invalid character), replace it with the constant string Invalid input.

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

JavaScript (ES6), 78 bytes

f=([c,...r],s='',k='GCTA'.indexOf(c))=>c?~k?f(r,s+'CGAU'[k]):'Invalid input':s

Test cases

f=([c,...r],s='',k='GCTA'.indexOf(c))=>c?~k?f(r,s+'CGAU'[k]):'Invalid input':s

console.log(f('C'           )) // 'G'
console.log(f('A'           )) // 'U'
console.log(f('ACGTGGTCTTAA')) // 'UGCACCAGAAUU'
console.log(f('XXX'         )) // 'Invalid Input'
console.log(f('ACGTXXXCTTAA')) // 'Invalid Input'


Without input validation (non-competing)

47 bytes using search():

f=([c,...r])=>c?'CGAU'['GCTA'.search(c)]+f(r):r

48 bytes using a hash:

f=([c,...r])=>c?'UCG_A'[parseInt(c,36)%5]+f(r):r
\$\endgroup\$
1
\$\begingroup\$

GNU sed, 70 43 bytes

s/^.*[^ATCG].*$/Invalid Input/
y/ATCG/UAGC/

Try it online!

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

C (clang) or MinGW, 110 bytes

f(s){for(char*t="GCTA",*o=s=strdup(s),*q;*o;o++)(q=strchr(t,*o))?*o="CGAU"[q-t]:(s="Invalid input!");puts(s);}

Try it online!

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

Red,118 114 bytes

func[s][t: copy{}foreach c s[append t switch/default to-word c[G[{C}]C[{G}]T[{A}]A[{U}]][return"Invalid Input"]]t]

Try it online!

Ungolfed:

f: func [s] [ 
    t: copy {}                              ; initialize t to an empty string
    foreach c s [                           ; for each character c of the input
        append t switch/default to-word c [ ; append to t the following if c is one of GCTA
            G [{C}]
            C [{G}]
            T [{A}]
            A [{U}] 
        ]
        [ return "Invalid Input" ]          ; otherwise return "Invalid Input"
    ]     
    t                                       ; return t
]
\$\endgroup\$
1
\$\begingroup\$

Python, 103 95 86 bytes

def f(b):
 try:return["CGAU"["GCTA".index(i)]for i in b]
 except:return"Invalid Input"

Or, if lowercase inputs count:

def f(b):
 try:return["cgau"["gcta".index(i.lower())]for i in b]
 except:return"Invalid Input"
\$\endgroup\$
  • 3
    \$\begingroup\$ Why not uuse "GCTA" and "CGAU" and remove the .lower()? \$\endgroup\$ – streetster Feb 18 '18 at 9:32
  • 1
    \$\begingroup\$ further to the above I think "acgt" should be considered invalid input. \$\endgroup\$ – Jonathan Allan Feb 18 '18 at 14:35
  • \$\begingroup\$ @streetster I wasn't sure whether or not the lowercase letters counted as valid inputs. \$\endgroup\$ – sonrad10 Feb 18 '18 at 19:39
  • 1
    \$\begingroup\$ Can't you inline a and c like try:return["CGAU"["GCTA".index(i)]for i in b]? \$\endgroup\$ – Laikoni Feb 19 '18 at 20:46
  • \$\begingroup\$ @Laikoni I didn't think of that, changed! \$\endgroup\$ – sonrad10 Feb 20 '18 at 11:02
1
\$\begingroup\$

CJam, 43 bytes

l{"GCTA"#"CGAU "=}%_S#){];"Invalid input"}&

Online interpreter: http://cjam.aditsu.net/

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

Batch, 192 bytes

@echo off
set/ps=
set t=%s:A=%
set t=%t:C=%
set t=%t:G=%
set t=%t:T=%
if not "%t%"=="" echo Invalid Input&exit/b
set s=%s:A=U%
set s=%s:C=A%
set s=%s:G=C%
set s=%s:A=G%
echo %s:T=A%

Takes input on STDIN.

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

Haskell, 75 bytes

f s|all(`elem`"GCTA")s=["UCG A"!!mod(fromEnum c)5|c<-s]
f _="Invalid Input"

Try it online! The mapping is done by taking the character values mod 5 and indexing into the string "UCG A".

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

Jelly,  24  23 bytes

“ɠ{>dʠ»ɓ,Ṛ;⁾TUyðḟ?“TGCA

A full program printing the result (a monadic link is  25  24 with a closing appended)

Try it online!

How?

“ɠ{>dʠ»ɓ,Ṛ;⁾TUyðḟ?“TGCA - Main Link: list of characters
                  “TGCA - literal list of characters = ['T','G','C','A']
                 ?      - if...
                ḟ       - ...condition: filter discard (empty is falsey)
“ɠ{>dʠ»                 - ...then: compressed string = "Invalid Input"
       ɓ       ð        - ...else: dyadic chain with swapped arguments:
         Ṛ              - reverse = ['A','C','G','T']
        ,               - pair = [['T','G','C','A'],['A','C','G','T']]
           ⁾TU          - literal list of characters = ['T','U']
          ;             - concatenate = [['T','G','C','A'],['A','C','G','T'],'T','U']
              y         -   translate...
                        -   ... 1: {'T'->'A';'G'->'C';'C'->'G';'A'->'T'}
                        -   ... 2: {'T'->'U'}
\$\endgroup\$
0
\$\begingroup\$

C, 128 bytes

k,l;f(S){char*s=S,b[l=strlen(s)],*t=b;for(;*t++=(k=*s++)-65?k-67?k-71?k-84?0:65:67:71:85;);puts(strlen(b)-l?"Invalid Input":b);}

Try it online!

Unrolled:

k, l;
f(S)
{
    char *s=S, b[l=strlen(s)], *t=b;
    for(; *t++ = (k=*s++)-65 ? k-67 ? k-71 ? k-84 ? 0 : 65 : 67 : 71 : 85;);
    puts(strlen(b)-l ? "Invalid Input" : b);
}
\$\endgroup\$
0
\$\begingroup\$

Perl 5 with -p, 39 bytes

y/GCTA/CGAU/<y///c?$_="Invalid Input":0

Saved 1 byte thanks to wastl!

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ Two other 41 bytes solutions (both -p): s/.*[^GCTA].*/Invalid Input/;y;GCTA;CGAU and y/GCTA/CGAU/<length?$_='Invalid Input':0 \$\endgroup\$ – wastl Feb 18 '18 at 11:15
  • \$\begingroup\$ @wastl Oh, nice. Using y///c instead of length your second saves a byte! Thank you! \$\endgroup\$ – Dom Hastings Feb 18 '18 at 13:01
  • 1
    \$\begingroup\$ We don't count flags as bytes anymore; instead, we count flags as separate languages altogether, so this answer is "Perl 5 + -p, 39 bytes" and not "Perl 5, 39 bytes + 1 (-p) = 40". \$\endgroup\$ – Erik the Outgolfer Feb 18 '18 at 13:07
  • \$\begingroup\$ Thanks @EriktheOutgolfer I keep forgetting this. Old habits and all that... \$\endgroup\$ – Dom Hastings Feb 18 '18 at 18:22
  • 1
    \$\begingroup\$ Well, it's my question over meta which has the consensus, no wonder I've been immediately used to it. :P \$\endgroup\$ – Erik the Outgolfer Feb 18 '18 at 18:24
0
\$\begingroup\$

R, 75 bytes

function(s)"if"(grepl("[^ACGT]",s),"Invalid Input",chartr("ACGT","UGCA",s))

Try it online!

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

APL+WIN, 66 bytes

Prompts for screen input of original string

('CGAU',⊂'Invalid Input')[(((⍴n)×~m)↑n),(m←0<+/(n←,'GTCA'⍳⎕)=5)↑5]
\$\endgroup\$
  • \$\begingroup\$ How many bytes? \$\endgroup\$ – Laurel Feb 19 '18 at 17:00
  • \$\begingroup\$ @Laurel Thanks for spotting my omission. Corrected. \$\endgroup\$ – Graham Feb 19 '18 at 17:41
  • \$\begingroup\$ @Laikoni That is strange I edited it, checked it and the count was there. Just gone back and it was gone. I have re-edited and checked and it is there now \$\endgroup\$ – Graham Feb 20 '18 at 16:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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