# # Intermediate Algorithm Scripting

Just for the record, my solutions for these exercises.

## # Sum numbers in a range.

``````function sumAll(arr) {
let newArr = arr.sort((a,b) => a - b);
let start = newArr[0]; //assumes that only two numbers are passed but not
let end = newArr[1]; // necessarily in the right order
let result = 0;
for (let i = start; i <= end; i++) {
result += i;
}
return result;
}
console.log(sumAll([12, 4]));
``````
1
2
3
4
5
6
7
8
9
10
11

## # Diff two arrays

The function I came up with does not deal with duplicates - if either array had more than one copy of an element which does not appear in the other, then those duplicates would be passed into the output, but the question did not ask for deduplication.

``````function diffArray(arr1, arr2) {
let onlyInArr1 = arr1.filter(n => !arr2.includes(n));
let onlyInArr2 = arr2.filter(n => !arr1.includes(n));
return onlyInArr1.concat(onlyInArr2);
}
console.log(diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]));
console.log(diffArray(["andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"]));
``````
1
2
3
4
5
6
7

## # Seek And Destroy

Remove elements from an array which match any number of following arguments.

``````function destroyer(arr) {
let args = Array.from(arguments); //arguments is not a true Array
let destroyedArr = args[0]; // first argument is the input array, arguments[0] also works
args.shift(); //remove the input array so only have the targets for removal
let result = destroyedArr.filter(n => !args.includes(n)); //just leave the ones that don't match
return result;
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3)); //[1,1]
console.log(destroyer(["possum", "trollo", 12, "safari", "hotdog", 92, 65, "grandma", "bugati", "trojan", "yacht"], "yacht", "possum", "trollo", "safari", "hotdog", "grandma", "bugati", "trojan")); //[12,92,65]
``````
1
2
3
4
5
6
7
8
9

## # Wherefore art thou

Some sloppy typing hindered me here. Here is the challenge.

Here is my solution:

``````function whatIsInAName(collection, source) {
var arr = [];
// Only change code below this line
let searchArr = arr.concat(collection);               //
let keysToFind = Object.keys(arguments[1]);           // get array, e.g. ["apple","bat"]
let valuesToFind = Object.values(arguments[1]);       // get array, e.g. [1,2]
let allMatched = true;                                // object has to contain all the targets
searchArr.forEach(function(c) {                       // loop through collection
allMatched = true;                                  //
for (let i = 0; i < keysToFind.length; i++){        // inner loop of targets
if (!(c[keysToFind[i]] == valuesToFind[i])) {     // if any match fails
allMatched = false;                             // reject it
}
}
if (allMatched){                                    // only push to result if all matched
arr.push(c);
}
});
// Only change code above this line
return arr;
}
console.log(whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" })); // [{ first: "Tybalt", last: "Capulet" }].
//whatIsInAName([{ "apple": 1 }, { "apple": 1 }, { "apple": 1, "bat": 2 }], { "apple": 1 }) should return [{ "apple": 1 }, { "apple": 1 }, { "apple": 1, "bat": 2 }].
//whatIsInAName([{ "apple": 1, "bat": 2 }, { "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "bat": 2 }) should return [{ "apple": 1, "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }].
``````
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

## # Intermediate Algorithm Scripting: Spinal Tap Case

Could not use split here because there is not always a separator between words, sometimes the words are separated by a non alphabetic character, but other times the next word simply begins with a capital Letter and no space.

``````function spinalCase(str) {
let strArr = str.trim().split("");        //gets each character in the string to loop over
let wordStarted = true;                   //assume that the first word begins with the first character
let words = [];
let word = "";
let alpha = /[a-zA-Z]/;
let capitalLetter = /[A-Z]/;
strArr.forEach(function(letter){                          //loop over all characters in the string
if(wordStarted){                                        //am building a word
if(alpha.test(letter)){                               //if its alphabetic going to append
if(capitalLetter.test(letter) && word.length > 0){  //if a capital letter will also start new
words.push(word);
word = "";
}
word += letter;
}
else{                                                 //not alpha
wordStarted = false;                                //so word is finished
word = "";                                          //reset
}
}
else{                                                   //not building a word
if(alpha.test(letter)){
wordStarted = true;                                 //only start new word on alphabetic char
word += letter;
}
}
});
if (word.length > 0) {words.push(word);}                  //capture last word
const reducer = (strSoFar, currentWord) => strSoFar + "-" + currentWord;
return words.map(word => word.toLowerCase()).reduce(reducer);
}
console.log(spinalCase('This Is   ,,   Spinal Tap')); //"this-is-spinal-tap"
console.log(spinalCase("thisIsSpinalTap")); //"this-is-spinal-tap"
console.log(spinalCase("AllThe-small Things")); //"all-the-small-things"
``````
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

## # Translate word to pig latin

``````function translatePigLatin(str) {
let vowel = /[aeiou]/;
let consonants = /^[^aeiou]*/; // 0 or more consonants at the beginning.
let cluster = str.match(consonants).toString();
if (cluster.length === 0){
return str + "way";     //words that begin with vowel just get way on the end
}
/*
take the consonant cluster and put it at the end and add 'ay' - this also works
if there are no vowels as the slice returns an empty string, slice without the optional
second argument takes string from the start point to the end of the string
*/
return str.slice(cluster.length) + cluster + "ay";
}
console.log(translatePigLatin("glove")); //oveglay
console.log(translatePigLatin("cymry")); //cymryay
console.log(translatePigLatin("albacore")); //albacoreway
``````
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

## # Search and Replace

Preserving the capitalisation of the original string replaced.

``````function myReplace(str, before, after) {
let regex = new RegExp(before,'g');   // => regex /Sleeping/g
let capitalLetter = /^[A-Z]/;         // ^ not necessary really
if (capitalLetter.test(before)){
after = after.charAt(0).toUpperCase() + after.slice(1);
}
return str.replace(regex, after);
}
console.log(myReplace("He is Sleeping on the couch", "Sleeping", "sitting")); //He is Sitting on the couch
``````
1
2
3
4
5
6
7
8
9

## # DNA Pairing

Input is a string of letters made up from ACGT, return is a nested array with each letter paired with its opposite, A with T, C with G and so on.

``````function pairElement(str) {
const bases = ["A", "C", "T", "G"];
const pairs = ["T", "G", "A", "C"];
let elems = str.split("");
return elems.map( elem => [elem, pairs[bases.indexOf(elem)]]);
}
pairElement("ATCGA"); //[["A","T"],["T","A"],["C","G"],["G","C"],["A","T"]]
``````
1
2
3
4
5
6
7

## # Missing Letters

Find the missing letter in a string of consecutive letters and return it, if no missing letter return undefined.

``````function fearNotLetter(str) {
const alphabet = 'abcdefghijklmnopqrstuvwxyz';
let start = alphabet.indexOf(str[0]);
for (let i = 0; i < str.length; i++){
if (str[i] !== alphabet[i+start]){
return alphabet[i+start];
}
}
return;
}
console.log(fearNotLetter("abcdefghjklmno")); //i
console.log(fearNotLetter("stvwx")); //u
``````
1
2
3
4
5
6
7
8
9
10
11
12

## # Unite unique

The coding challenge here is to return a single array from a number of input arrays but only to include each number once in whatever order they were originally. The code I submitted passed the test but is incomplete as it only accounts for one level of nesting, and if for example 5 and [5] were both included it would not skip whichever came second. Adding that in would be complicated in this structure.

``````function uniteUnique(arr) {
let arrs = Array.from(arguments);
let result = [];
arrs.forEach(function(elem){
elem.forEach(function(inner){
//console.log(Array.isArray(inner));
if(!result.includes(inner)){
result.push(inner);
}
})
});
return result;
}
console.log(uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1])); //[1, 3, 2, 5, 4]
console.log(uniteUnique([1, 3, 2], [1, [5]], [2, [4]])); //[1, 3, 2, [5], [4]]
``````
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

## # Equivalent of the PHP htmlentities function

This is just a matter of stringing replaces together.

``````function convertHTML(str) {
let colonRegex = /:/g;
let colon = '&colon;';
let ampRegex = /&/g;
let amp = '&amp;';
let lessRegex = /</g;
let less = '&lt;';
let greaterRegex = />/g;
let greater = '&gt;';
let doubleRegex = /\"/g;
let double = '&quot;';
let singleRegex = /\'/g;
let single = '&apos;';
return str.replace(ampRegex, amp).replace(colonRegex, colon).replace(lessRegex, less).replace(greaterRegex, greater).replace(doubleRegex,double).replace(singleRegex, single);
}
console.log(convertHTML('Stuff in "quotation marks"'));
``````
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

## # Sum All Odd Fibonacci Numbers

``````function sumFibs(num) {
let fibs = [1,1];
let a = 1;
let b = 1;
let c = 1;
do {
c = a+b;
fibs.push(c);
a = b;
b = c;
}
while (c < num);
if(c>num){fibs.pop();}
return fibs.filter(x => x % 2).reduce((acc, curr) => acc + curr);
}
console.log(sumFibs(75024)); // 60696
``````
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

## # Sum all Primes

``````function sumPrimes(num) {
let primes = [];
let isPrime = false;
for (let i=2; i<=num; i++){ //loop integers from 1st prime
isPrime = true;
for (let j=2; j<=(i/2); j++ ){  //look for factors
if(i % j === 0){              //if a factor
isPrime = false;            //this number not a prime
break;                      //stop looking
}
}
if(isPrime){primes.push(i);}    //if it was prime..
}
return primes.reduce((acc, curr) => acc + curr);
}
console.log(sumPrimes(977)); //73156
``````
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

## # Small Common Multiplier

Of a sequence of numbers, for example input is `[1,5]` have to find the lowest common multiple of 1 and 5 which is also divisible by 2,3,and 4, which is 60.

``````function smallestCommons(arr) {
let sortedArr = arr.sort((a,b) => a - b);
let sequence = []
for (let i = sortedArr[0]; i<= sortedArr[1]; i++){
sequence.push(i);
}
let allDivisors = false;
let candidate = 0;
let multiplier = 1;
do {
candidate = sortedArr[0] * sortedArr[1] * multiplier;     //try each multiple of the two numbers
allDivisors = true;
sequence.forEach(function(i){
if(!(candidate % i === 0)){                             //if any of the sequence is not a divisor
allDivisors = false;                                  //then this is not a candidate
}                                                       //cannot break from a foreach loop
});                                                       //so should use a for loop instead !
multiplier += 1;
}
while (allDivisors == false);
return candidate;
}
smallestCommons([13,1]); //360360
``````
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23