From b8c228936203497e6668d873fe8a9a339beabcc3 Mon Sep 17 00:00:00 2001 From: Vankog Date: Sun, 17 Sep 2017 18:38:56 +0200 Subject: [PATCH] implemented nucleotide-count exercise --- config.json | 13 ++++ exercises/nucleotide-count/README.md | 62 +++++++++++++++ exercises/nucleotide-count/example.js | 24 ++++++ .../nucleotide-count/nucleotide-count.spec.js | 78 +++++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 exercises/nucleotide-count/README.md create mode 100644 exercises/nucleotide-count/example.js create mode 100644 exercises/nucleotide-count/nucleotide-count.spec.js diff --git a/config.json b/config.json index 7a2fc65a72..2e8a66223e 100644 --- a/config.json +++ b/config.json @@ -52,6 +52,19 @@ "Transforming" ] }, + { + "core": true, + "difficulty": 2, + "slug": "nucleotide-count", + "topics": [ + "filtering", + "pattern-matching", + "strings", + "test-driven-development" + ], + "unlocked_by": "rna-transcription", + "uuid": "9debee8e-003d-4eb2-bf97-6d3764d024ca" + }, { "uuid": "da5b2b34-a1a7-4970-81f9-4665d875398b", "slug": "pangram", diff --git a/exercises/nucleotide-count/README.md b/exercises/nucleotide-count/README.md new file mode 100644 index 0000000000..52aaaf3d2d --- /dev/null +++ b/exercises/nucleotide-count/README.md @@ -0,0 +1,62 @@ +# Nucleotide Count + +Given a DNA string, compute how many times each nucleotide occurs in the string. + +DNA is represented by an alphabet of the following symbols: 'A', 'C', +'G', and 'T'. + +Each symbol represents a nucleotide, which is a fancy name for the +particular molecules that happen to make up a large part of DNA. + +Shortest intro to biochemistry EVAR: + +- twigs are to birds nests as +- nucleotides are to DNA and RNA as +- amino acids are to proteins as +- sugar is to starch as +- oh crap lipids + +I'm not going to talk about lipids because they're crazy complex. + +So back to nucleotides. + +DNA contains four types of them: adenine (`A`), cytosine (`C`), guanine +(`G`), and thymine (`T`). + +RNA contains a slightly different set of nucleotides, but we don't care +about that for now. + +## Setup + +Go through the setup instructions for ECMAScript to +install the necessary dependencies: + +http://exercism.io/languages/ecmascript + +## Requirements + +Install assignment dependencies: + +```bash +$ npm install +``` + +## Making the test suite pass + +Execute the tests with: + +```bash +$ npm test +``` + +In the test suites all tests but the first have been skipped. + +Once you get a test passing, you can enable the next one by +changing `xtest` to `test`. + +## Source + +The Calculating DNA Nucleotides_problem at Rosalind [http://rosalind.info/problems/dna/](http://rosalind.info/problems/dna/) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/nucleotide-count/example.js b/exercises/nucleotide-count/example.js new file mode 100644 index 0000000000..c06294b3a7 --- /dev/null +++ b/exercises/nucleotide-count/example.js @@ -0,0 +1,24 @@ +const countIn = (strand, nucleotide) => [...strand] + .filter(x => x.includes(nucleotide)) + .length; + +class Dna { + constructor(strand) { + this.dna = strand || ''; + if (!/^[ACGT]*$/.test(this.dna)) { + throw new Error(`Input strand must not contain anything but A, C, G or T: ${this.dna}`); + } + this.nucleotidesCount = new Map([ + ['A', countIn(this.dna, 'A')], + ['C', countIn(this.dna, 'C')], + ['G', countIn(this.dna, 'G')], + ['T', countIn(this.dna, 'T')], + ]); + } + count(nucleotide) { + const count = this.nucleotidesCount.get(nucleotide); + return count || 0; + } +} + +module.exports = Dna; diff --git a/exercises/nucleotide-count/nucleotide-count.spec.js b/exercises/nucleotide-count/nucleotide-count.spec.js new file mode 100644 index 0000000000..2a4016b2a2 --- /dev/null +++ b/exercises/nucleotide-count/nucleotide-count.spec.js @@ -0,0 +1,78 @@ +import Dna from './nucleotide-count'; + +describe('DNA', () => { + it('counts an undefined DNA strand as 0', () => { + const dna = new Dna(); + expect(dna.count('A')).toEqual(0); + expect(dna.count('C')).toEqual(0); + expect(dna.count('G')).toEqual(0); + expect(dna.count('T')).toEqual(0); + }); + + xit('counts a single repetitive nucleotide correctly.', () => { + const strand = 'CCCCC'; + expect(new Dna(strand).count(strand[0])).toEqual(strand.length); + }); + + xit('returns the same count values steadily.', () => { + const strand = 'AACCGGTTAACCGGTT'; + const countOfFirstChar = 4; + const acid = new Dna(strand); + + expect(acid.count(strand[0])).toEqual(countOfFirstChar); + expect(acid.count(strand[0])).toEqual(countOfFirstChar); + expect(acid.count(strand[0])).toEqual(countOfFirstChar); + }); + + xit('counts 0 for unknown or invalid nucleotides.', () => { + const strand = 'ACGTACGT'; + + // U-nucleotide as part of the RNA + expect(new Dna(strand).count('U')).toEqual(0); + // no-real-nucleotide + expect(new Dna(strand).count('Z')).toEqual(0); + // special-character-nucleotides + expect(new Dna(strand).count('Ä')).toEqual(0); + expect(new Dna(strand).count('×')).toEqual(0); + // 'poocleotide' (aka a Unicode character nucleotide) + expect(new Dna(strand).count('💩')).toEqual(0); + }); + + xit('counts 0 for nucleotide sequences, even if they match.', () => { + const strand = 'ACACACGTCACGTC'; + + // matching AC + let includedSubStrand = strand.substr(0, 2); + expect(new Dna(strand).count(includedSubStrand)).toEqual(0); + + // matching GTC + includedSubStrand = strand.substr(6, 3); + expect(new Dna(strand).count(includedSubStrand)).toEqual(0); + + // non-matching GC + expect(new Dna(strand).count('GC')).toEqual(0); + }); + + xit('counts all nucleotides correctly', () => { + const strand = 'AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC'; + const dna = new Dna(strand); + const expected = { + A: 20, + T: 21, + C: 12, + G: 17, + }; + const testVals = { + A: dna.count('A'), + T: dna.count('T'), + C: dna.count('C'), + G: dna.count('G'), + }; + + expect(testVals).toEqual(expected); + }); + + xit('validates DNA for correct nucleotides', () => { + expect(() => new Dna('JOHNNYAPPLESEED')).toThrow(); + }); +});