madbernard: a long angled pier (Default)
Just did a Coderbyte challenge that was, "given an array of numbers that could be positive or negative but which will not include 0, return 'Arithmetic' for arrays where there's the same distance between all the numbers, 'Geometric' for arrays where there's the same multiple between all the numbers, and -1 for everything else." My answer isn't the best it could possibly be (I feel that I'm using Math.abs poorly, and I should have taken a moment more to make the reduce part bring back the biggest number in the difference array... averages can be deceiving), but looking at answers from unnamed other people, several of them don't even work. This one only compares the gap in numbers of the first two and last two in the array:
function ArithGeo(arr) { 
  var isArithmetic=(arr[1]-arr[0]==arr[arr.length-1]-arr[arr.length-2]);
  var isGeometric=(arr[1]/arr[0]==arr[arr.length-1]/arr[arr.length-2]);
  // code goes here  
  if(!isArithmetic&&!isGeometric){//is not special
    return -1;
  }else{
    return (isArithmetic)?'Arithmetic':'Geometric';
  }
}
It can be defeated with [1,2,45,99,100]. I saw this same pattern three times in like six answers I looked over. Interesting to catch stuff that the tests don't. When I started this post I was feeling a cheerful about not being at the bottom of the heap, but now I'm a bit sad. Anyway, here's my answer. Tell me about better ways of checking that every number in an array is the same... I could have done another for loop, "if difference array [i] !== difference array [0] return false"...
function ArithGeo(arr) { 
  var geo = [];
  var arith = [];
  for (var i = 0; i < arr.length - 1; i++) {
    geo.push(Math.abs(arr[i + 1] / arr[i]));
    arith.push(Math.abs(arr[i + 1] - arr[i]));
  }
  var sumGeo = geo.reduce(function(prev, curr){
    return prev + curr;
  });
  var sumArith = arith.reduce(function(prev, curr){
    return prev + curr;
  });
  if (sumGeo / geo.length === geo[0]) {return 'Geometric';}
  if (sumArith / arith.length === arith[0]) {return 'Arithmetic';}
  return -1; 
}
madbernard: a long angled pier (Default)
Here's one I thought would be simple, which wasn't. The problem is, "return a count of all the vowels (not y) in a string." I thought I'd use regex.exec to capture an array of vowels and find the length of the array... But it only ever returned length 2. I see in the Mozilla Developer Network info page that RexExp.length is 2, but I don't know why I'm getting that here. Can someone troubleshoot?
function VowelCount(str) { 
  var re = /([aeiou])/ig;
  var arr = re.exec(str);
  console.log(arr);
  return arr.length; 
}

console.log(VowelCount('moooo'));
So I pivoted to for loops and came up with this,
function VowelCount(str) { 
  var re = /[aeiou]/i;
  var count = 0;
  for (var i = 0; i < str.length; i++) {
    if (re.test(str.charAt(i))) {
      count += 1;
      console.log(i);
  }
  return count; 
}
This also took some troubleshooting, since the count was wrong when I was using the 'g' flag in the regex. I'm also not sure why that was. Other people I looked at also had mangled looking answers, though of course Matt Larsh has something good,
function VowelCount(str) { 
  var vowels = str.match(/[aeiou]/g);
  return vowels.length;
}
Looks like I need to bone up on str.match.
madbernard: a long angled pier (Default)
Last evening I had a moment and tried the Coderbyte challenge "when given a string of single letters, plusses, and equals signs, return true only if every letter has a plus on both sides". I came up with a four part if statement reliant on regexes.
function SimpleSymbols(str) {
  if (/(\+\w\+)+/g.test(str) && !/^\w/g.test(str) && !/=\w/g.test(str) && !/\w(?!\+)/g.test(str)) 
  {return true;}
  else {return false;}
}
In English, that's if there is a plus on either side of a letter, and if there is no letter at the start of the string, and if there is no letter with an equals sign immediately in front of it, and if there is no letter that is not followed by a plus sign... Then true.

Ben, who does JS for a living, gave me the learning that if there's more than one regex, it's probably not ideal... "There's so many edge cases". Makes sense. So, later, the Coderbyte challenge appears, "when given a string of lowercase letters, if there is an a followed by a b three spots later, return true". And I'm like, "I'll use a for loop, like we were talking about last night!"Read more... )
madbernard: a long angled pier (Default)
Challenge 5 was, given a number between 1 and 1000, add up all the numbers inclusive in that set. Obviously I could repurpose Matt Larsh's recursive function to do this, so I did so, and it worked first try. Woo! Though, no one else seems to be doing +=. I wonder if this would be super wrong if I wasn't recursing and thus seeing it only once each function call? Or do they just like num + SimpleAdding(stuff)?
function SimpleAdding(num) {
  if (num === 1) {
    return 1;  
  }
  else {
    return num += SimpleAdding(num - 1);
  }      
}
Challenge 6 was one I hadn't yet solved in Free Code Camp: Capitalize every word in a string. I abandoned a couple different paths while trying for speed, and eventually came up with this answer that seems cludgy:
function LetterCapitalize(str) { 
  var foo = str.split('');
  var bar = [];
  bar.push(foo[0].toUpperCase());
  for(var i = 1; i < foo.length; i++) {
    if (foo[i - 1] === ' ') {
      bar.push(foo[i].toUpperCase());
    }
    else {
      bar.push(foo[i]);
    }    
  }
  console.log(bar.join(''));
  return bar.join('');
}
LetterCapitalize('to see how to enter arguments in JavaScript');
I tried replacing the space in the if statement with /\s/ and that didn't work, nor did /\s/g; I'm not sure why not.

One of my abandoned paths was to do a str.replace(regex, function) but I wasn't getting the function to work... So I was super curious to see what Matt Larsh did, and sure enough he did something cool:
function LetterCapitalize(str) { 
  return str.replace(/\b[a-z]/g,function(c){return c.toUpperCase()});
}
That "\b" was something I thought should exist, but didn't find: the signal for "match a word boundary". I just tried /\b\w/g and that works, too; I suppose his way is better, though, since it limits the capitalization to only things that we absolutely know need capitalizing. Unless if \w includes accented letters and other slightly less usual things? My RegEx skillz are not yet l33t and m4d.
madbernard: a long angled pier (Default)
Remembering these from last week: Challenge 3 was another I'd done before, "find the longest word in the sentence", and I got a few more refinements in my answer: I used a regular expression to create the first array; and (having discussed it with Ben) I used an empty string as the initializing value. The previous stab at this Reduce, where I was trying to initialize with 0, was comparing apples and oranges in the form of numbers and strings.
function LongestWord(sen) { 
  var arr = sen.split(/(\w+)/g);
  var foo = arr.reduce(function(prev, curr){
    if(prev.length < curr.length){
      return curr;
    } else {return prev;}
  }, '');
  return foo; 
}
Looking over other answers, I think reduce is by far the most elegant path. Wooo! Arrays FTW!

Challenge 4 was ...a journey. Read more... )
madbernard: a long angled pier (Default)
Factorial happened last week, also; the CoderByte challenge was, we'll test on numbers between 1 and 18, give us that number multiplied by every non-0 integer less than it. Ben-the-housemate suggested that this could be done recursively, so I tried that first, but didn't hack it; so, given the ticking clock, I aborted to the exact same decreasing for-loop plan I'd used last week. Looking through other answers was gratifying... I was among the most elegant! I found the recursive method from user mattlarsh, in a tiny tidy package:
function FirstFactorial(num) { 
  return num<=1?1:num*(FirstFactorial(num-1)); 
}
He's using the ternary operator there, the shortest possible way to say if/then. IF: the num is less than or equal to 1, DO THIS: return 1, AND IF IT'S NOT: multiply the num by FirstFactorial num-1. So once he has a stack of not-quite-resolved functions and the num gets to 1, it returns 1 and then the rest of the stack has all the numbers it needs to work with and can resolve the final return.

My first pass on recursion was the below, and I got stack overflow (infinite program), which I can see now is because the num kept getting bigger but the recursion would only end when the num got to 0.
function FirstFactorial(num) { 
if (num > 0) {
num *= (num - 1);
FirstFactorial(num);
}
  return num; 
}

FirstFactorial(5);   
madbernard: a long angled pier (Default)
I looked at the Hack Reactor suggestions for what one should be able to do before applying, and headed over to http://www.coderbyte.com to try their easy track. They score submissions based not only on correctness, but on time, which is not at all my bag. I think when I saw that a year ago I just turned away, even though a friend suggested doing it on my own time and then pasting the answer in... I might do that in the future.

Their first question was the exact same as I saw last week; reverse a string. I came up with this, which, amusingly, is not what I did last week. It uses the join method of arrays that I was searching for last week, so I'm pleased that knowledge is in me...
function FirstReverse(str) { 
  var hold = [];
  for(var i = str.length - 1; i >= 0 ; i--){
    hold.push(str[i]);
  }
  var foo = hold.join("");
  return foo; 
}

FirstReverse("stuff");           
Also, heeey, check out the respect of spacing in that code block. I thought there were HTML tags about code, and found <code> and thought that was it... Ben the housemate says code isn't really a HTML tag and turned me on to <pre>. Thanks!

Anyway, a good thing about CoderByte: they let you see what other people did, after, answering the socrating question of my friend Catherine about whether I looked at other people's solutions. There's a solution like mine above, but relying on methods of strings and arrays that I wasn't aware of; and that solution lets one do everything in a single line!
function FirstReverse(str) { 
  return str.split('').reverse().join('');
}
Way more elegant.
madbernard: a long angled pier (Default)
The next Free Code Camp exercise is to find the length of the longest word in a string (and all of their test strings are free of anything but letters and single spaces). Good points: I had no trouble getting the shape of the solution, and split totally worked great. Actually doing the proper syntax for Reduce required a lot of searching, though, and eventually I basically copied a bit from this webpage about getting comfy with arrays. I should work through that website sometime... Most of the failed reduce trials I don't have copies of, but one that I don't understand is that when I had a 0 in the place I thought was for initial value, right after the anonymous function and before the console.log error-catching readout, here: }, 0);
console.log(foo.length);
what I got out of the function was only 0. Baffling. Below is code that works. :)

function findLongestWord(str) {
var words = str.split(' ');
var foo = words.reduce(function(prevWord, thisWord){
if (thisWord.length > prevWord.length) {
return thisWord;
}
else {
return prevWord;
}
});
console.log(foo.length);
return foo.length;
}

findLongestWord('The quick brown fox jumped over the lazy dog');
madbernard: a long angled pier (Default)
So, 4 was trivial, which was great: make a function that factorializes numbers. Like, 5! is 1 * 2 * 3 * 4 * 5 = 120.

function factorialize(num) {
for (var i = (num - 1); i > 0; i--) {
num *= i;
}
return num;
}

factorialize(5);

But 5... I feel like I shouldn't have to make my own function that takes an array and jams it all into a single string without commas separating the bits. But the concat stuff I was looking at in the Mozilla Developer Network wasn't working that way (even though their example shows it should. So baffled).

And I feel like there must be some way to not declare like 7 variables... But I couldn't figure out how to chain these methods/functions. Anyway: here it is, a function that checks if a statement is a palindrome (ignoring all the non-letter things! The RegEx stuff was honestly fun learning).

function reverseString(str) {
var reverseStr = '';
for (var i = str.length - 1; i > -1; i--){
reverseStr += str[i];
}
return reverseStr;
}

function arrToRevStr(arr) {
var str = '';
for (var i = arr.length - 1; i > -1; i--){
str += arr[i];
}
return str;
}

function palindrome(str) {
var cleanStrArray = /(\w)/g.exec(str);
var cleanStr = arrToRevStr(cleanStrArray);
var cleanStrLow = cleanStr.toLowerCase();

var reverseStr = reverseString(str);
var cleanReverseStrArray = /(\w)/g.exec(reverseStr);
var cleanReverseStr = arrToRevStr(cleanReverseStrArray);
var cleanReverseStrLow = cleanReverseStr.toLowerCase();

if (cleanStrLow == cleanReverseStrLow) {return true;}
else {return false;}
}

palindrome("eye");
madbernard: a long angled pier (Default)
I feel like I've reversed a string before... I vaguely remember something about halving the length and swapping things around the middle. But this time, when Free Code Camp asked for it as their very first JavaScript coding exercise, I just looped through the entire thing. Woooo!

function reverseString(str) {
var reverseStr = '';
for (var i = str.length - 1; i > -1; i--){
reverseStr += str[i];
console.log(reverseStr);
}
return reverseStr;
}

reverseString('hello');

At first I had just defined the reverseString variable as "var reverseStr;", and the readout I was getting from that console.log in the loop was "NaNo" "NaNol" etc. Second debugging step, when I made the start point of the loop i = str.length - 1 instead of i = str.length, I got "undefinedo" "undefinedol" "undefinedoll" etc. So in the first case it was trying to add the nothing in "hello"[5] to NaN, since why, the sensible programming language thinks, would I be trying to use an addition operator, +, on anything but a number? I'm not sure why trying to add "o" worked; I suppose JavaScript decided that the o it was getting meant that it should be adding to a string or object or some non-number thing, but that string or object or whatever wasn't defined. It's nice that when it failed at adding it relapsed to concatenating.

...I suspect this is a terrible implementation of reversing a string. Any takers?

The Free Code Camp at this point suggests I should be pairing, and a nice guy in the chat room linked me up with a copy of Screenhero (they've joined Slack and are not taking new signups unless someone already inside invites you in), which they suggest is good for being able to remotely cowork and see everything on another screen... Another guy in the chat suggested coderpad.io or another .io solution instead, as less dangerous and better functioning. What do people think, re: screen sharing programs?

More wins

Jun. 2nd, 2015 12:51 pm
madbernard: a long angled pier (Default)
Last week I was working on a problem that my housemate Ben suggested: the Animal Guessing game, where the code asks you to think of an animal, then builds up a tree of potential animals that you could guess and yes or no questions that would lead there, taking inputs you give it. He remembered it from some 101 class he took, and it turned out to be pretty great, since it has a lot of small bits that you can check as you go, and it creates something that's (arguably) actually worth having. Below is my solution. Maybe sometime I'll come back to it to add the ability to save games, or I'll put it on a website and wean it away from Prompt and Alert. I'd also like to make functions out of the stuff I'm repeating... Like function positiveWords, negativeWords, unrecognizedInput...

function Guess(animal, question, nextYes, nextNo) {
this.animal = animal;
this.question = question;
this.nextYes = nextYes;
this.yesPath = 0;
this.nextNo = nextNo;
}

var thisGameTree = [];
var start = new Guess();
var animalMessage = ["Welcome to the animal guessing game! Teach the program to guess what animal you're thinking of!", "Think of an animal. Can be an animal you've thought of before, can be a new animal."];
var avoidRestartMessage = 0;

var questionGame = function () {
if (avoidRestartMessage === 0) alert(animalMessage[thisGameTree.length]);
if (!start.animal) {
start.animal = prompt("What is the animal you are thinking of?");
start.question = prompt("Please write a yes or no question that would help figure out what your animal is.");
var yesIsForThisAnimal = prompt("Is \"yes\" the right answer for \"" + start.question + "\" for " + start.animal + "?").toLowerCase();
if (yesIsForThisAnimal == "yes") {
start.yesPath = 1;
}
if (yesIsForThisAnimal == "no") {
start.yesPath = 2;
}
alert("Ok, new try!");
avoidRestartMessage = 0;
if (thisGameTree.length === 0) {
thisGameTree.push(start);
}
start = thisGameTree[0];
questionGame();
} else {
var questionAnswer = prompt(start.question).toLowerCase();
//yes path
if (questionAnswer == "yes" && start.yesPath === 1) {
var routingYesAnswer = prompt("Is " + start.animal + " your animal?").toLowerCase();
if (routingYesAnswer == "yes") {
alert("You win! You taught the computer to read your mind!");
} else if (routingYesAnswer == "no") {
//route deeper in
avoidRestartMessage = 1;
if (start.nextYes === undefined) {
start.nextYes = new Guess();
start = start.nextYes;
questionGame();
} else {
start = start.nextYes;
questionGame();
}
} else {
alert("I'm confused! Please only type yes or no!");
questionGame();
}
}
//yes path
else if (questionAnswer == "yes") {

//route deeper in
avoidRestartMessage = 1;
if (start.nextYes === undefined) {
start.nextYes = new Guess();
start = start.nextYes;
questionGame();
} else {
start = start.nextYes;
questionGame();
}
}

//no path, on the right track
else if (questionAnswer == "no" && start.yesPath === 2) {
var routingNo2Answer = prompt("Is " + start.animal + " your animal?").toLowerCase();
if (routingNo2Answer == "yes") {
alert("You win! You taught the computer to read your mind!");
} else if (routingNo2Answer == "no" || routingNoAnswer == "yes") {
//route deeper in
avoidRestartMessage = 1;
if (start.nextNo === undefined) {
start.nextNo = new Guess();
start = start.nextNo;
questionGame();
} else {
start = start.nextNo;
questionGame();
}
} else {
alert("I beg your pardon. Please only type yes or no!");
questionGame();
}

}
//no path
else if (questionAnswer == "no") {
//route deeper in
avoidRestartMessage = 1;
if (start.nextNo === undefined) {
start.nextNo = new Guess();
start = start.nextNo;
questionGame();
} else {
start = start.nextNo;
questionGame();
}
}
//mop up path
else {
alert("Sorry, what? Please only type yes or no!");
questionGame();
}
}
console.log(thisGameTree);
};

Second win: today I was poking around to find a Javascript MOOC, and came across this. In lesson 1.2, He starts talking about Sublime Text, an editor I downloaded last week because JSBin wasn't any good for tidying up the indenting as I shifted if statments around. It turns out that one needs to download a separate package to make Sublime do that... So today I added the Package Handler, and then the jsFormat package. Like a boss! Thanks Stack Overflow!

Third win: I use Opera as a secondary browser, with the idea being that I can be logged into Facebook on Opera and not pollute normal browsing with Facebook's messes. But since Firefox was clogged with tabs, I'm using Opera for posting to Dreamwidth also, and with the increased use, it became intolerable that I couldn't Ctrl-PgUp and -PgDwn to shift tabs. Finally thanks to this link I determined that in Settings, with Advanced Keyboard Shortcuts clicked, it's possible to change or add Keyboard Shortcuts. Wooooooo!

Mad Out.
madbernard: a long angled pier (Default)
There I was on Eloquent Javascript's problem 5.4, http://eloquentjavascript.net/05_higher_order.html#h_jr7hZiuR7+

The for loop seemed simple, but what I came up with wasn't processing "isNaN" as a function.

var every = function (array, compare) {
for (var i = 0; i < array.length; i++) {
if (array.i !== compare)
return false;
else return true;
}
};

console.log(every([NaN, NaN, NaN], isNaN));
// → should be true, but was showing as false
console.log(every([NaN, NaN, 4], isNaN));
// → false


Putting the "compare" in the if condition in () parentheses (because I had a memory that some form of parentheses would make javascript try to find the value of a thing... Thinking about this, that was probably a memory from getting values of keys, done with [], which in this case I believe would flag "compare" as an array) didn't fix it. Trying for != to allow for type conversion didn't fix it.

I looked at the hints, and they didn't talk about making functions do their thing; they talked about setting up the loop like "forEach". I took an abortive stab at redoing the loop to use forEach... This didn't run, and the linter in JSBin was sad about my use of break. (I'm still not sure what's up with break.)

function every (array) {
array.forEach(function(compare) {
if (array !== compare) {
break;
}
else return true;
});
return false;
}


I tabbed over to the annotated book: https://docs.google.com/document/d/1aa2-HtUglQrAps31s4LdTPVsiFb1BxhyjZolxeezzcI/edit?_escaped_fragment_=#!
Predicate functions were never defined in the book so I’ll quickly explain them here.

A predicate function is a function that returns true or false based on some condition. In this problem, we’re using isNaN(testValue), which returns true if testValue is NaN (remember this means not a number), and false otherwise.

Huh. At first that seemed a bit unfair, a new unexplained type of function. But then, a closer reading would have indicated that the compare thing had to be a function; and I'd even previously went back to the appearance of isNaN in Eloquent Javascript and managed to whizz past the part where it was summoned into action like so, isNan("some thing").

The working answer,
var every = function (array, compare) {
for (var i = 0; i < array.length; i++) {
if (!compare(array[i]))
return false;
}
return true;
};

And "some" is trivial from there.
Page generated Sep. 22nd, 2017 07:00 pm
Powered by Dreamwidth Studios