Visit the rna-transcription exercise on Exercism to read the full instructions and download the exercise files.
Dig Deeper
Use a Dictionary
Using a Dictionary
using System.Collections.Generic;
using System.Linq;
public static class RnaTranscription
{
public static string ToRna(string dna) =>
new(dna.Select(nucleotide => Complements[nucleotide]).ToArray());
private static readonly Dictionary<char, char> Complements =
new() { ['G'] = 'C', ['C'] = 'G', ['T'] = 'A', ['A'] = 'U' };
}
The first step is to decide how we want to iterate over and transform the nucleotides.
As the string class implements the IEnumerable<char> interface, this allows us to call
LINQ’s Select() method on it, which can do both the iteration and the transformation in one go!
dna.Select(nucleotide => TODO)
Within the Select() method’s lambda argument, we’ll need to translate the nucleotide to its complement.
We can do that by creating a dictionary with the key being the nucleotide and the value its complement:
private static readonly Dictionary<char, char> Complements = new Dictionary<char, char>
{
['G'] = 'C',
['C'] = 'G',
['T'] = 'A',
['A'] = 'U'
};
Using a target-typed new expression, we can omit the second Dictionary<char, char> type:
private static readonly Dictionary<char, char> Complements = new()
{
['G'] = 'C',
['C'] = 'G',
['T'] = 'A',
['A'] = 'U'
};
We can then use this dictionary in our lambda to get the nucleotide’s complement:
dna.Select(nucleotide => Complements[nucleotide])
This will return a new IEnumerable<char>, which we can convert back to a string by first converting it to a char[] and then passing that to a string constructor:
public static string ToRna(string dna)
{
return new string(dna.Select(nucleotide => Complements[nucleotide]).ToArray());
}
As this has just a single return statement, we can convert it to an [expression-bodied method][expression-bodied-method]:
public static string ToRna(string dna) =>
new string(dna.Select(nucleotide => Complements[nucleotide]).ToArray());
Finally, we can once again use a target-typed new expression to replace new string with just new:
public static string ToRna(string dna) =>
new(dna.Select(nucleotide => Complements[nucleotide]).ToArray());
And with that we have a concise, working implementation!
Alternative: using a foreach loop
You could also use a regular foreach loop instead of LINQ:
public static string ToRna(string dna)
{
var rna = "";
foreach (var nucleotide in dna)
rna += Complements[nucleotide];
return rna;
}
Use a switch expression
Using a switch expression
using System.Linq;
public static class RnaTranscription
{
public static string ToRna(string dna) =>
new(dna.Select(Complement).ToArray());
private static char Complement(char nucleotide) =>
nucleotide switch
{
'G' => 'C',
'C' => 'G',
'T' => 'A',
'A' => 'U'
};
}
The first step is to decide how we want to iterate over and transform the nucleotides.
As the string class implements the IEnumerable<char> interface, this allows us to call
LINQ’s Select() method on it, which can do both the iteration and the transformation in one go!
dna.Select(nucleotide => TODO)
Within the Select() method’s lambda argument, we’ll need to translate the nucleotide to its complement.
Let’s implement a new Complement() method that takes a nucleotide, pattern matches on its value a using a switch expression and returns its complement:
private static char Complement(char nucleotide)
{
return nucleotide switch
{
'G' => 'C',
'C' => 'G',
'T' => 'A',
'A' => 'U'
};
}
As this method returns a single expression, we can convert it to an [expression-bodied method][expression-bodied-method]:
private static char Complement(char nucleotide) =>
nucleotide switch
{
'G' => 'C',
'C' => 'G',
'T' => 'A',
'A' => 'U'
};
We can then use this method in our lambda:
dna.Select(nucleotide => Complement(nucleotide))
As the lambda is doing nothing more than passing the argument to a method, we can rewrite it to a method group:
dna.Select(Complement)
This call will return a new IEnumerable<char>, which we can convert back to a string by first converting it to a char[] and then passing that to a string constructor:
public static string ToRna(string dna)
{
return new string(dna.Select(Complement).ToArray());
}
As this has just a single return statement, we can convert it to an [expression-bodied method][expression-bodied-method]:
public static string ToRna(string dna) =>
new string(dna.Select(Complement).ToArray());
Finally, we can once again use a target-typed new expression to replace new string with just new:
public static string ToRna(string dna) =>
new(dna.Select(Complement).ToArray());
And with that we have a concise, working implementation!
Alternative: using a switch statement
You could also replace the switch expression with a regular switch:
private static char Complement(char nucleotide)
{
switch (nucleotide)
{
case 'G':
return 'C';
case 'C':
return 'G';
case 'T':
return 'A';
case 'A':
return 'U';
default:
throw new ArgumentOutOfRangeException(nameof(nucleotide));
}
}
This is not only more verbose, but it also requires the default arm to be added as well as not allowing the method to be written an an expression-bodied member.
Alternative: using a foreach loop
For the iteration, you could also use a regular foreach loop instead of LINQ:
public static string ToRna(string dna)
{
var rna = "";
foreach (var nucleotide in dna)
rna += Complement(nucleotide);
return rna;
}
Source: Exercism csharp/rna-transcription