Oh so close to the end of the Mysterious Organism Project Extensions

Hi everyone.

I’m tasked with using an existing method, compareDNA, to find the two most related instances of pAequor.

I was able to compare all the DNA strands using my compareDNA method, but I can’t easily identify the two strands with the highest overlap without manually scrolling through the lengthy list of logged comparisons.

Any assistance is much appreciated.

Project link:
https://www.codecademy.com/journeys/full-stack-engineer/paths/fscj-22-building-interactive-websites/tracks/fscp-22-javascript-syntax-part-ii-c8ddbace-1463-4797-ae12-503c7b0f9552/modules/wdcp-22-mysterious-organism-8119c94c-f8eb-4254-8520-dfe4afc233a1/projects/mysterious-organism

The code in question is at the very bottom, which uses the compareDNA method in the pAequorFactory object.

// Randomly selects a base and return the base ('A','T','C', or 'G')
const returnRandBase = () => {
  const dnaBases = ['A', 'T', 'C', 'G'];
  return dnaBases[Math.floor(Math.random() * 4)]; //returns random index value between 0 and 3 that is assigned to corresponding dnaBase 
};

// Generates an array containing 15 bases to represent a single DNA strand with 15 bases.
const mockUpStrand = () => {
  const newStrand = [];
  for (let i = 0; i < 15; i++) {
    newStrand.push(returnRandBase());
    // console.log(newStrand);
  }
  return newStrand;
  };


//Factory function to create objects with two parameters, specimen number and DNA strand 
let pAequorFactory = (specimenNum, dna) => {
  return {
    specimenNum,
    dna,
    
// Method to randomly select a DNA base and revise it to a new base     
  mutate() {
    let randomBase = Math.floor(Math.random() * 15);//Randomly selects one of 15 existing DNA bases to replace
    let newBase = returnRandBase(this.dna[randomBase]);//Creates a new DNA base to replace existing one
    while (newBase === this.dna[randomBase]) { // Ensures existing dna base and new base are different 
      randomBase = Math.floor(Math.random() * 15);
      newBase = returnRandBase(this.dna[randomBase]);
    }
    this.dna[randomBase] = newBase;
  },

// Method to compare two DNA strands and compute percentage of shared DNA      
  compareDNA (specimenNum, dna) {
    let specimenMatches = 0;
    console.log(`Original DNA: ${this.dna}.`);
    console.log(`Comparison DNA: ${dna}.`);
    for (let i = 0; i < dna.length; i++){
      if (dna[i] === this.dna[i]){
        specimenMatches++;
      } else {
        continue;
      }
  } 
      console.log(`Specimen #${this.specimenNum} and #${specimenNum} have ${specimenMatches} corresponding DNA matches.`);
      let percentOverlap = ((specimenMatches/dna.length) * 100).toFixed(1);
      // console.log(`Shared DNA is ${percentOverlap}% of total DNA.`); 
},

// Method to evaluate a DNA strand. Strands consisting of at least 60% 'C' and 'G' bases are likely to survive. 
    willLikelySurvive () {
      let basesCG = 0;
      this.dna.forEach(element => {
      if(element === 'C' || element === 'G'){
          basesCG++;
      }})
      return (basesCG / this.dna.length) >= 0.6; 
    },

//Returns complementary DNA strand
    complementStrand () {
      let compStrand = [];
      for(let i=0; i < 15; i++) {
        switch (this.dna[i]) {
          case 'A':
            compStrand.push(this.dna[i] = 'T');
            break;
          case 'T':
            compStrand.push(this.dna[i] = 'A');
            break;
          case 'C':
            compStrand.push(this.dna[i] = 'G');
            break;
          case 'G':
            compStrand.push(this.dna[i] = 'C');
            break;
        }
      }
      return compStrand;
    }
  }
}

// Compares randomly generated DNA strand with inputted strand
pAequorFactory(1, mockUpStrand()).compareDNA(2, ['A', 'T', 'C', 'G', 'A', 'T', 'C', 'G', 'A', 'T', 'C', 'G', 'A', 'T', 'C']);

//Prints true if the DNA will survive (i.e. 60%+ of strands are 'C' and 'G'); otherwise false.
console.log(pAequorFactory(1, mockUpStrand()).willLikelySurvive());

//Creates 30 instances of pAequor that can survive in their natural habitat (i.e. 60%+ of strands are 'C' and 'G')
let pAequor30 = [];
let specimenNum = 1;

while (pAequor30.length < 30) { 
  let dna = mockUpStrand(); // Generates DNA strand
  let survive = pAequorFactory(specimenNum, dna).willLikelySurvive(); //Tests if strand will survive
  if (survive) { //Only strands that survive are added to the final array.
    pAequor30.push({specimenNum, dna}); 
    specimenNum++;
  } else {
    continue;
  } 
}

console.log(pAequor30);


// Prints base DNA and associated complementary DNA 
let baseDNA = mockUpStrand();
console.log('Base DNA:');
console.log(baseDNA);
console.log('Complementary DNA:');
console.log(pAequorFactory(2, baseDNA).complementStrand());

// console.log(pAequorFactory(1,pAequor30[0].dna).compareDNA(pAequor30[1]));


//Use .compareDNA() to find the two most related instances of pAequor.

let specNum1;
let specNum2;
let highMatch = 0;

for (let i = 0; i < pAequor30.length-1; i++) { //Loops through 29 strands to avoid comparing DNA #30 with itself.
  for (let j = i+1; j < pAequor30.length; j++) { //compares each DNA strand to all other DNA strands
  pAequorFactory(pAequor30[i].specimenNum,pAequor30[i].dna).compareDNA(pAequor30[j].specimenNum,pAequor30[j].dna);
   if (this.specimenMatches > highMatch) {
    highMatch = this.specimenMatches;
    console.log(highMatch);
    specNum1 = pAequor30[i].specimenNum;
    specNum2 = pAequor30[j].specimenNum;
   } else { 
     continue;
   }  
   }
   }
   console.log(`Specimen #${specNum1} and specimen #${specNum2} have the highest DNA overlap, with ${highMatch} matching pairs`);

I cleaned up the code to make the output easier to to read. I still haven’t figured out my initial question if anyone has any ideas.

const returnRandBase = () => {
  const dnaBases = ['A', 'T', 'C', 'G'];
  return dnaBases[Math.floor(Math.random() * 4)]; //returns random index value between 0 and 3 that is assigned to corresponding dnaBase 
};

// Generates an array containing 15 bases to represent a single DNA strand with 15 bases.
const mockUpStrand = () => {
  const newStrand = [];
  for (let i = 0; i < 15; i++) {
    newStrand.push(returnRandBase());
  }
  return newStrand;
  };


//Factory function to create objects with two parameters, specimen number and DNA strand 
let pAequorFactory = (specimenNum, dna) => {
  return {
    specimenNum,
    dna,
    
// Method to randomly select a DNA base and revise it to a new base     
  mutate() {
    let randomBase = Math.floor(Math.random() * 15);//Randomly selects one of 15 existing DNA bases to replace
    let newBase = returnRandBase(this.dna[randomBase]);//Creates a new DNA base to replace existing one
    while (newBase === this.dna[randomBase]) { // Ensures existing dna base and new base are different 
      randomBase = Math.floor(Math.random() * 15);
      newBase = returnRandBase(this.dna[randomBase]);
    }
    this.dna[randomBase] = newBase;
  },

// Method to compare two DNA strands and compute percentage of shared DNA      
  compareDNA (specimenNum, dna) {
    let specimenMatches = 0;
    console.log(`Original DNA: ${this.dna}.`);
    console.log(`Comparison DNA: ${dna}.`);
    for (let i = 0; i < dna.length; i++){
      if (dna[i] === this.dna[i]){
        specimenMatches++;
      } 
  } 
      console.log(`Specimen #${this.specimenNum} and #${specimenNum} have ${specimenMatches} corresponding DNA matches.`);
      let percentOverlap = ((specimenMatches/dna.length) * 100).toFixed(1);
      console.log(`Shared DNA is ${percentOverlap}% of total DNA.`); 
},

// Method to evaluate a DNA strand. Strands consisting of at least 60% 'C' and 'G' bases are likely to survive. 
    willLikelySurvive () {
      let basesCG = 0;
      this.dna.forEach(element => {
      if(element === 'C' || element === 'G'){
          basesCG++;
      }})
      return (basesCG / this.dna.length) >= 0.6; 
    },

//Returns complementary DNA strand
    complementStrand () {
      let compStrand = [];
      for(let i=0; i < 15; i++) {
        switch (this.dna[i]) {
          case 'A':
            compStrand.push(this.dna[i] = 'T');
            break;
          case 'T':
            compStrand.push(this.dna[i] = 'A');
            break;
          case 'C':
            compStrand.push(this.dna[i] = 'G');
            break;
          case 'G':
            compStrand.push(this.dna[i] = 'C');
            break;
        }
      }
      return compStrand;
    }
  }
}

// Compares randomly generated DNA strand with inputted strand
pAequorFactory(1, mockUpStrand()).compareDNA(2, ['A', 'T', 'C', 'G', 'A', 'T', 'C', 'G', 'A', 'T', 'C', 'G', 'A', 'T', 'C']);

//Prints true if the DNA will survive (i.e. 60%+ of strands are 'C' and 'G'); otherwise false.
console.log(pAequorFactory(1, mockUpStrand()).willLikelySurvive());

//Creates 30 instances of pAequor that can survive in their natural habitat (i.e. 60%+ of strands are 'C' and 'G')
let pAequor30 = [];
let specimenNum = 1;

while (pAequor30.length < 30) { 
  let dna = mockUpStrand(); // Generates DNA strand
  let survive = pAequorFactory(specimenNum, dna).willLikelySurvive(); //Tests if strand will survive
  if (survive) { //Only strands that survive are added to the final array.
    pAequor30.push({specimenNum, dna}); 
    specimenNum++;
  } 
}

console.log(pAequor30);


// Prints base DNA and associated complementary DNA 
let baseDNA = mockUpStrand();
console.log('Base DNA:');
console.log(baseDNA);
console.log('Complementary DNA:');
console.log(pAequorFactory(2, baseDNA).complementStrand());



//Use .compareDNA() to find the two most related instances of pAequor.
let specNum1;
let specNum2;
let highMatch = 0;

for (let i = 0; i < pAequor30.length-1; i++) { //Loops through 29 strands to avoid comparing DNA #30 with itself.
  for (let j = i+1; j < pAequor30.length; j++) { //compares each DNA strand to all other DNA strands
  pAequorFactory(pAequor30[i].specimenNum,pAequor30[i].dna).compareDNA(pAequor30[j].specimenNum,pAequor30[j].dna);
   if (this.specimenMatches > highMatch) {
    highMatch = this.specimenMatches;
    console.log(highMatch);
    specNum1 = pAequor30[i].specimenNum;
    specNum2 = pAequor30[j].specimenNum;
   }  
   }
   }
   console.log(`Specimen #${specNum1} and specimen #${specNum2} have the highest DNA overlap, with ${highMatch} matching pairs`);

I don’t think there’s a way to do the comparisons more efficiently - every comparison needs to be made.

However, you don’t need the else condition that just continues the loop. The loop will naturally progress if the if condition doesn’t attain.

Thanks Taylor. I removed the unnecessary else statements.

I have been trying for a while to come up with a solution and I can’t find one either.

I think it’s time for me to move on from this project since all the other requirements have been met.

1 Like