CoDEVIANT #3 (3/23/19) @ 1:06am-ish

I need to sleep more. Maybe also pipe Philip Glass into my room when I do these entries, to complete the smug, bearded rando doing “tech things, maaaan” appearance. Then, and ONLY THEN will I know I’m legit. It couldn’t get any worse unless I was in a Starbucks or a local independent coffee shop that you’ve never heard of where no body get’s drinks for months at a time — and yet they keep waiting — for their head barista to finish their foreign excursion out to Colombia to pick beans by hands and walk them back.

Problem 1:

Find the Capitals

Instructions: Write a function that takes a single string (word) as argument. The function must return an ordered list containing the indexes of all capital letters in the string.

We need to be able to have our code pass the following kind of test:

Test.assertSimilar( capitals(‘CodEWaRs’), [0,3,4,6] );

If you were here for CoDEVIANT #1, you’ll probably have a little light bulb go off like I did.

I actually solved this on my first try because I remembered the technique we used involving RegEx. 💅

How Adrian solved it:

var capitals = function (word) {   let answer = [];   for(let i = 0; i <= word.length; i++){      if(/[A-Z]/.test(word[i])){         answer.push(i);      }   }   return answer;};

Let’s break it down:

Gotta keep it gangsta.
  • We create an answer array.
  • We create a for-loop that iterates through each letter in the word argument that is passed into the function.
  • We search for any letter matching the selection range [A-Z] while omitting a “/i” because we DO CARE about what case the letter is in. And we test this matching against the given character in the string passed to us in the argument word.
  • If it is a capital, then we push what the for-loop’s i variable represents into the answer array.
  • We return array, and feel like a badass.

Now what is the “Best Practices” solution?

var capitals = function (word) {   return word.split(‘’).reduce(function(memo, v, i) {      return v === v.toUpperCase() ? memo.concat(i) : memo;   }, []);};

Okay here’s what I see right off the bat:

  • We return something right away….gangsta, and gutsy.
  • We use .split( ) on the word string. This will turn a string into an array. And when you pass in a pair of empty quote marks as an argument to the .split( ) method, then the string turns into an array which makes each individual letter or character in the string into an array element
var word = ‘punk’;console.log( word.split(‘’) ); // results in [‘p’,’u’,’n’,’k’]
  • We use the .reduce( ) method immediately on the array that we create from the use of the .split( ) method.
  • *Hot tip, you can chain methods together basically infinitely, which is pretty dope.

Inside the .reduce( ) method you enter a callback function that takes 3 arguments

  1. memo
  2. v
  3. i

.reduce( ) method.

Confession Time

I’m not super, über familiar with using the reduce method nor with the use of a custom callback function inside of it. So let’s try to learn something today, shall we?

So some basic facts on the .reduce( ) method.

  • The .reduce( ) method reduces arrays to a single value.
  • It takes a callback function as its FIRST ARGUMENT and then also executes this provided callback function for each value of the array from left-to-right
  • The provided callback function (its called provided by me because YOU write it) takes an accumulator as it’s first argument. In the fancy “Best Practices” solution we are studying, the accumulator is called memo.
  • An accumulator is required.
  • The callback function also requires a currentValue argument which represents the current value of the element being worked on at the moment. In our “Best Practices” solution we are studying, the currentValue argument is called v.
  • A currentValue argument is required
  • The callback function also can take an optional currentIndex argument which stands for the array-index for the current array element being worked on at the moment. In our “Best Practices” solution we are studying, the currentIndex argument is called i.
  • The currentIndex argument is optional
  • The callback function can also take the array object that current element belongs to…it’s optional and our solution doesn’t use it…so…meh.
  • The .reduce( ) method, for its SECOND ARGUMENT…and this one is kind of trippy…it is a value to be passed to the function as the initial value, aka the accumulator…basically it will be a stand in for memo.
  • This is outside of the callback function and it’s sub-arguments that we covered already.

So…where were we?

In the function we are trying to get passing, we use .split(‘’) to turn word into an array that has each letter of the word as an array element. Then we use the .reduce( — ) method on our new array.

In place of the , we have memo as the initial value, we have v as the value, and we have i representing the index of the value being referenced in the array we just made at this point. Then we also have that super important empty array as the second argument of the .reduce( — ) method.

Then inside the code block of the function that is a part of the .reduce( — ) method we use a conditional/ternary operator to see if

the value (v) is equal to v.upperCase( ), .upperCase is a string method that gets a string value and makes it upper-case.

If v is equal to itself being uppercased, then memo will have i (the index) concatenated to it with .concat(i)

.concat( ) is an array method that merges two or more arrays or a value into an array, without deleting any members of the originals (if both parties are arrays). What we are doing is having that empty array at the end of the .reduce( ) ’s use be what memo represents. So when we .concat(i) things into memo, we are placing elements into the blank array at the end.

Now IF v IS NOT equal to itself, nothing gets added to memo and it is just left alone and we wait for .reduce( ) to finish it’s job of reducing an array into a single value.

What I learned

  • Reduce is a pretty cool method to be used to
  • Leveraging a combination of string and array methods can help you avoid extra loops.
  • Always seek to use methods when possible. Think of them as short cuts that other developers have put for you so you can avoid having towers of code

Problem 2:

Deodorant Evaporator

Instructions:

This program tests the life of an evaporator containing a gas.

We know the content of the evaporator (content in ml), the percentage of foam or gas lost every day (evap_per_day) and the threshold (threshold) in percentage beyond which the evaporator is no longer useful. All numbers are strictly positive.

The program reports the nth day (as an integer) on which the evaporator will be out of use.

Note : Content is in fact not necessary in the body of the function “evaporator”, you can use it or not use it, as you wish. Some people might prefer to reason with content, some other with percentages only. It’s up to you but you must keep it as a parameter because the tests have it as an argument.

What we start out with:

function evaporator(content, evap_per_day, threshold){return -1;}

The aim would be for this test case to pass:

Test.assertEquals(evaporator(10,10,10),22);

If you pass in 10 as each of the arguments, it would be the 22nd day that the evaporator would not work anymore.

…. I’m not going to lie. I suck big time at things with percentages and math…then you wrap it all up with coding stuff? Forget it. This reminds me of those puzzles you see in games where you have to get a certain amount of liquid in one of 3 containers and you have to shift the contents of the 3 containers. I typically go straight for a walkthrough when I encounter them. I hate them. I tried console logging the arguments…but my time is precious and I can’t hope to figure this one out by myself.

Maybe if I’m feeling frisky later, I’ll give it a shot after I have a better understanding of the moving parts of this problem once I study the best practices solution.

Which is:

function evaporator(content, evap_per_day, threshold) {threshold = threshold / 100evap_per_day = evap_per_day / 100return Math.ceil(Math.log(threshold) / Math.log(1-evap_per_day))}

So…what I can see here is the following:

  • We turn the threshold argument into a percent by automatically dividing it by 100.
  • We turn the evap_per_day argument into a percent by automatically dividing it by 100 as well.
  • We dip in to the Math group of JavaScript to do operations involving mathematics:
  • .ceil( ) — rounds a number upward to its nearest integer.
  • .log( ) — returns the natural logarithm of a number…

I know jack*(&@ about logarithms.

**Googles around in embarrassment for 5 seconds

So a logarithm according to a quick google search is:

a quantity representing the power to which a fixed number (the base) must be raised to produce a given number.

So the logarithm is the exponent number that you have to have as a superscript to ‘2’ (if 2 is the base) when you’re trying to get the ’16’.

24 = 16

In my example here, 4 is the logarithm of 16 when the base is 2.

*adjusts glasses*

Bearing all this in mind

  • .log( ) — returns the natural logarithm of a number…when the base is the natural base …
  • Natural base equals roughly 2.718.
  • If you .log(10) then your result will be 2.302585092994046
  • Then if you multiply the base (2.718) by itself 2.302585092994046 times you will get approximately 10…like 9.9976ish to be more precise.

When you use two instances of the .log( ) math-method in a parenthetical operation, the first value wrapped in a .log( ) is the value we’re trying to find the logarithm for. The second value wrapped in a .log( ) math-method in the same parenthetical operation will be the base.

If we had Math.log(8)/Math.log(2), our answer would be 3, because you would need to multiply 2 by itself 3 times to get to 8.

If we had Math.log(16)/Math.log(2), our answer would be 4, because you would need to multiply 2 by itself 4 times to get to 16.

So let’s think about our function:

function evaporator(content, evap_per_day, threshold) {threshold = threshold / 100evap_per_day = evap_per_day / 100return Math.ceil(Math.log(threshold) / Math.log(1-evap_per_day))}

For examples sake let’s have 10, 10, and 10 be the stand ins for arguments content, evap_per_day, & threshold.

threshold becomes itself divided by 10 => .10

evap_per_day becomes itself divided by 10 => .10

Then we vow to round up whatever answer we get *using .ceil( )* from using Math.log( ) on our threshold value divided by

Math.log( ), which holds an argument of the evap_per_day value we modified subtracted from 1.

As far as I can tell, the 1 business is there to make the argument reflect the remainder of material that is left in a given day after subtracting how much is used up in that day.

Bearing this in mind, we are trying to figure out how to get .10 by multiplying .90 a mysterious number of times against itself.

Throw this number in and it’s 22. Cool…but I am a shit math student and I want to test it…How can I know for sure? (hopefully).

Go into a calculator and enter .90 and raise that by the power of 22. and you’ll get 0.098477090218361

That’s not 10!

And you’re right, it really isn’t. BUT do remember that we turned all our values into percentages inside of our function. What this means is that we need to shift the decimal point two places to the right.

That gives us approximately 9.8477. Then do recall that we are wrapping the uses of the .log( ) math method with another math method by the name of .ceil( ) . This rounds our number up, which turns 9.8477 into 10. I guess that’s how we would get our content

So this is basically a glorified division problem with a bit of exponent play…I may revisit this at a later time. But for now I need to get some rest.

Oh yeah…

Here’s some Philip Glass:

https://www.youtube.com/watch?v=6Stu7h7Qup8

is a web developer, opera singer, actor, and lover of cats. (adrian-rosales.tech)