-4
\$\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\$
8
  • 19
    \$\begingroup\$ Boo-urns to input validation! \$\endgroup\$
    – Shaggy
    Feb 18, 2018 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, 2018 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\$
    – DELETE_ME
    Feb 18, 2018 at 15:21
  • 3
    \$\begingroup\$ (Recommend sandbox) \$\endgroup\$
    – DELETE_ME
    Feb 18, 2018 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, 2018 at 15:59

18 Answers 18

1
\$\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\$
1
  • 2
    \$\begingroup\$ Moar guacamole pls \$\endgroup\$ Feb 19, 2018 at 2:11
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\$

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\$
5
  • 3
    \$\begingroup\$ Why not uuse "GCTA" and "CGAU" and remove the .lower()? \$\endgroup\$
    – mkst
    Feb 18, 2018 at 9:32
  • 1
    \$\begingroup\$ further to the above I think "acgt" should be considered invalid input. \$\endgroup\$ Feb 18, 2018 at 14:35
  • \$\begingroup\$ @streetster I wasn't sure whether or not the lowercase letters counted as valid inputs. \$\endgroup\$
    – AvahW
    Feb 18, 2018 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, 2018 at 20:46
  • \$\begingroup\$ @Laikoni I didn't think of that, changed! \$\endgroup\$
    – AvahW
    Feb 20, 2018 at 11:02
1
\$\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\$
3
  • \$\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, 2018 at 19:54
  • \$\begingroup\$ @ovs Thanks! Is there any consensus on map objects? \$\endgroup\$
    – Laikoni
    Feb 22, 2018 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, 2018 at 5:53
1
\$\begingroup\$

CJam, 43 bytes

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

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

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

Python 3, 82 79 67 bytes

thanks to Laikoni for -3 bytes!
-12 bytes by looking at this 3 years later.

lambda s:{*s}-{*'ACGT'}and'Invalid Input'or s.translate('UCG A'*17)

Try it online!

str.translate takes any kind of collection of characters or codepoints that can be indexed into with an integer, in this case we use a string.

c ord(c) ord(c)%5 ('UCG A'*20)[ord(c)]
'A' 65 0 'U'
'C' 67 2 'G'
'G' 71 1 'C'
'T' 84 4 'A'
\$\endgroup\$
1
  • \$\begingroup\$ 79 bytes with "".join("UCG A"[ord(c)%5]for c in s): Try it online! \$\endgroup\$
    – Laikoni
    Feb 19, 2018 at 20:48
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\$

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\$
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\$
5
  • 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, 2018 at 11:15
  • \$\begingroup\$ @wastl Oh, nice. Using y///c instead of length your second saves a byte! Thank you! \$\endgroup\$ Feb 18, 2018 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\$ Feb 18, 2018 at 13:07
  • \$\begingroup\$ Thanks @EriktheOutgolfer I keep forgetting this. Old habits and all that... \$\endgroup\$ Feb 18, 2018 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\$ Feb 18, 2018 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\$
3
  • \$\begingroup\$ How many bytes? \$\endgroup\$
    – Laurel
    Feb 19, 2018 at 17:00
  • \$\begingroup\$ @Laurel Thanks for spotting my omission. Corrected. \$\endgroup\$
    – Graham
    Feb 19, 2018 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, 2018 at 16:49

Your Answer

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

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