Binary Search Tree in Ruby

I am officially a Flatiron School graduate!! 12 weeks of learning Ruby, Object Oriented Programming, Test Driven Development, RSpec, Model View Controller, REST, CRUD, rack middleware, Sinatra, Ruby on Rails, Active Record, SQL, JavaScript, jQuery, AJAX, Handlebars and Ember.js. But most importantly coming out with the knowledge of how to approach and learn a new language. I look forward to my life after Flatiron and what new languages and frameworks I’ll learn.

I wanted to touch upon a topic we started covering in our last week at Flatiron, which were data structures and sorting algorithms. This week reminded me of my few years of taking computer science courses, creating our own stacks, queues and linked lists. Writing sorting algorithms such as quicksort, mergesort and bubble sort. I was ecstatic to find out we were covering these topics! Remembering how much fun I had with these is partially what got me to change careers and enroll in Flatiron School in the first place. Even back in week 1 I was asking myself, what kind of sort does Ruby use? I learned so many sorts long ago, which one is it? After some Google-ing, interestingly enough, Ruby uses the quicksort algorithm for its sort method over mergesort.

Binary Search Tree

So one of my favorite problems that I came across was constructing your own Binary Search Tree(BST). I am going to walk through my process, but first we need to know what a BST is. A BST is a series of connecting nodes, where each node contains data, a left and a right. The left and right are pointers to a subtree of nodes where left is less than or equal to and right is greater than.

With this information we can start by creating our Binary Search Tree class which will represent our data structure. The walkthrough will consist of the structure and inserting into the BST.

1
2
3
class BST

end


Back to what a BST contains: data, left and right. Data will represent the data we store and left and right will represent subtrees.

1
2
3
4
5
6
7
class BST
  attr_accessor :data, :left, :right

  def initialize(data)
    @data = data
  end
end


Great! Now that we have the basic structure of the BST, we will need to be able to insert data into our BST class. Lets create a insert method which takes in 1 argument, data. I’m going to go ahead and pseudocode my thought process of how I think it works.

1
2
3
4
5
6
7
8
  def insert(data)
    # 1 - Start at top of the tree
    # 2 - Find which direction insert should be
    # 3 - Check that direction if it is nil
    # 3a - If nil insert into that location
    # 3b - If not nil, change top of tree location to that node
    # 4 - Repeat step 1
  end


We start at the top of the tree and keep track of the location. Following this, compare the data being inserted into our tree with the current location. This will determine if we are going left or right. If that direction results in a nil, we have reached our destination! We insert here, but if not we will need to change the current location to the top of the subtree.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  def insert(data)
    # 1 - Start at top of the tree √
    # 2 - Find which direction insert should be √
    # 3 - Check that direction if it is nil √
    # 3a - If nil insert into that location √
    # 3b - If not nil, change top of tree location to that node √
    # 4 - Repeat step 1

    current_location = self
    if current_location.data >= data
      if current_location.left
        current_location = current_location.left
      else
        current_location.left = BST.new(data)
      end
    else
      if current_location.right
        current_location = current_location.right
      else
        current_location.right = BST.new(data)
      end
    end
  end


We want to keep doing this process until the data has been inserted into the correct location. Since the number of times this loop will run is unknown, a while or until loop will do the trick with a placeholder variable for confirmation of when the loop is finished.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  def insert(data)
    current_location = self
    inserted = false

    until inserted
      if current_location.data >= data
        if current_location.left
          current_location = current_location.left
        else
          current_location.left = BST.new(data)
          inserted = true
        end
      else
        if current_location.right
          current_location = current_location.right
        else
          current_location.right = BST.new(data)
          inserted = true
        end
      end
    end
  end


Running some tests that were developed prior and eureka!! It works! While our task is complete, I’m not satisfied. To me this looks dirty. The 2 variables declared outside the loop, the loop itself, the seemingly repetitive code inside the loop and all the if-else statements!! I needed to refractor this. So back to thinking about the 5 steps, it appears the first 4 steps are repeated on BST instances, where each time all that is changing is the BST is becoming a subtree of itself. It seems like this can be done recursively.

1
2
3
4
5
  def insert(data)
    # 1 - Find which direction insert should be
    # 2a - If nil insert into that location
    # 2b - Else call insert method again on that subtree
  end


With recursion I am able to clean up the code to something I am satisfied with.

1
2
3
4
5
6
7
8
9
10
11
  def insert(data)
    # 1 - Find which direction insert should be √
    # 2a - If nil insert into that location √
    # 2b - Else call insert method again on that subtree √

    if self.data >= data
      self.left == nil ? self.left = BST.new(data) : self.left.insert(data)
    else
      self.right == nil ? self.right = BST.new(data) : self.right.insert(data)
    end
  end


This was just the first step in creating the BST data structure. Next I’ll explore deletion, searching and sorting in Binary Search Trees.

My First Open Source Contribution

Over this past weekend, I contributed to my first open source project! Special thanks to Aidan Feldman and Tute Costa for organizing this meetup at the Thoughtbot offices in New York City.

To me, contributing to a real world open source project seemed scary and far from reality. Who am I to contribute with only 10 weeks programming experience. I feel I am not the only person who thinks this. However, after this meetup I’d like to say that that fear is gone and it have been replaced with excitement for the future. I want to share some tips I learned at the meetup from the mentors and the overall experience that got me over that fear. Hopefully this helps those in taking their first steps into the open source community.

Quickly I’m going to go over the work flow with open source projects (my open source hub of choice is github).

  1. FORK their repo and clone from your fork. DO NOT clone straight from their repo!
  2. Make a BRANCH! If you are going to start editing, make a branch off your forked repo.
  3. Once you have made changes and wish to submit them to the creators, make a PULL request with an explanation of your edits.
  1. Best open source projects for you may be those you already use
    • You already know the purpose and uses
    • Reading through their source code will improve your understand of the project
    • Examples:
      • Ruby gems
  2. Going into open source projects you've never used
    • No fear, just try to install the project
    • Installation and working with their readme may be where you can contribute
  3. Documentation
    • Creators probably haven't installed their project on a machine since they first created it
    • Edit readme to help new comers with installation
  4. Next Steps
    • Explore their project in how it works and its uses
    • Browse their source code
    • Take a look at their current issues
    • Or even raise an issue of your own
    • Rinse and repeat

Happy contributing!!

JavaScript Toolbox

Coming from Ruby to JavaScript was more difficult than I thought it would be. The main difference to me: Documentation. Ruby has ruby-doc.org which has a well written and well organized dictionary for the entire language. While Javascript, I was primarily looking through w3schools and Modzilla’s documentation. Both not as well organized compared to Ruby’s. A part of my learning process is knowing what is available to me. Nothing I found was to my liking so I decided to gather all the information on the basic methods. What I came up with was surprisingly small. The JavaScript methods library was tiny compared to Ruby. So I compiled most of the methods (ones that I saw useful for me at this moment) for Numbers, Strings and Arrays with definitions and examples along with each.

Number
Method Description Example
#toString() Returns a string of that number 100.toString()
#=> "100"
#toExponential(num=0) Returns the exponential of a float as a string, cannot be an integer (num option of how many decimal places) 150.0.toExponential(4)
#=> "1.5000e+2"
#toFixed(num=0) Returns a string with the decimal places fixed to the num and rounds 150.3261.toFixed(2)
#=> "150.33"
#toPrecision(num=length) Returns a string of the number with a fixed length from num 150.3261.toPrecision(2)
#=> "1.5e+2"
String
Method Description Example
#indexOf(string) Returns the index of the first occurrence, returns -1 if none are found 'hello'.indexOf('l');
#=> 2
#indexLastOf(string) Returns the index of the last occurrence, returns -1 if none are found 'welcome'.indexLastOf('e');
#=> 6
#search(string) Same as #indexOf(string) except it allows for the search of regular expressions 't0'.search(/[0-9]/);
#=> 1
#match(string) Searches a string against a string or regular expression and returns the match in an array 'mY'.match(/[A-Z]/);
#=> ["Y"]
#charAt(num) Returns the character at the num index and returned empty string if out of range 'blog'.charAt(2);
#=> "o"
#split('x') Splits string by 'x' into an array 'string'.split('');
#=> ["s", "t", "r", "i", "n", "g"]
#concat(*args) Takes in as many string arguments and combines them into one 'java'.concat('scr', 'ipt');
#=> "javascript"
#slice(num1, num2) Returns the sting from index num1 to num2 not including num2, can accept negative numbers 'table'.slice(1,-1);
#=> "abl"
#substring(num1, num2) Same as #slice(num1, num2) except it cannot accept negative numbers 'enjoy'.substring(1, 3);
#=> "ej"
#substr(num1, num2) Returns a string where the substring starts at index of num1 to num2 characters 'yourself'.substr(1, 4);
#=> "ours"
#replace(string1, string2) Finds and replaces the first instance of string1 with string2, then returns the resulting string 'flatiron'.replace('iron', 'school');
#=> "flatschool"
#toUpperCase() Uppercase the entire string 'flatiron'.upUpperCase();
#=> "FLATIRON"
#toLowerCase() Lowercase the entire string 'FLATIRON'.upUpperCase();
#=> "flatiron"
#trim() Removes white space at the beginning and end of a string ' flatiron? '.trim()
#=> "flatiron?"
Array
Method Description Example
#concat(*arrs) Join multiple arrays into one [1,2,3].concat([4,5,6], [7,8,9]);
#=> [1,2,3,4,5,6,7,8,9]
#join('x') Joins each array element into a string separated by 'x' ('x' is optional, where the default is ',') ['flatiron', 'school'].join(' ');
#=> "flatiron school"
#indexOf(ele) Search array for the first matching element and returns the index, -1 if nothing is found [1,2,3,2].indexOf(2);
#=> 1
#lastIndexOf(ele) Search array for last matching element and returns the index, -1 if nothing is found[1,2,3,2].indexOf(2);
#=> 3
#pop() Removes and returns the last element of the array[1,2,3,2].pop();
#=> 2
#push(ele) Adds element to the end of the array and returns the length of the new array['h','e','l','l'].push('o');
#=> 5
#reverse() Reserve the elements of the array and returns the new array, this is destructive [1,2,3].reverse();
#=> [3,2,1]
#shift() Removes and returns the first element of the array [1,2,3,2].shift();
#=> 1
#unshift() Adds element to the beginning of the array and returns the length of the new array [1,2,3,2].unshift(1);
#=> 5
#sort() Sorts and returns the array, this is destructive [3,2,1].sort();
#=> [1,2,3]
#slice(num1, num2) Starts at index num1 and slices to index num2 not included, and returns the resulting array. [0,1,2,3,4,5].slice(1,3);
#=> [1,2]
#splice(num1, num2, *args) num1 represents the starting point, num2 represents the number of elements to remove and the *args is optional for any additions to be added to the array. Return value is an array of the removed elements ["h", "e", "l", "l", "o"].splice(1,2,9,8,7) => ["h", 9, 8, 7, "l", "o"]
#=> ["e", "l"]
Array Enumerable
Method Description Example
#every( function( element, index, array ) { return condition } ) Evaluates to true if callback function evaluates to be true for each element [1,2,3].every( function( element ) { return isFinite( element ) } );
#=> true
#filter( function( element, index, array ) { return condition } ) Like #select in Ruby, returns an array with elements who's callback function returned true [1,2,3,4,5].filter( function( element ) { return element > 3 } );
#=> [4, 5]
#forEach( function( element, index, array ) { do something } ) Like #each in Ruby, does something for each element in the array [1,2].forEach( function( element, index, array ) { console.log( element ) } );
#=> 1 #=> 2
#map( function( element, index, array ) { return something } ) Like #each in Ruby, creates an array of same length with returned values [1,2].map( function( element, index, array ){ return element + index } );
#=> [1, 3]
#reduce( function( previousValue, currentValue, index, array ) { return new previousValue }, initialValue ) Similar to #inject in Ruby, iterates through each element where previousValue initially starts off as initialValue and currentValue is the element. The return of the first iteration becomes the new previousValue and so on where the return is the final return. [1,2,3].reduce( function( a, b, index, array ) { return a+b }, 10 );
#=> 16
#some( function( element, index, array ) { return condition } ) Evaluates to true if callback function evaluates to be true for at least one element [1,2,3].some( function( element ) { return element/2 == 1 } );
#=> true
Global Methods
Method Description Example
#eval() Evaluates and executes a string eval('1+1');
#=> 2
#isFinite() Returns true or false either the input is a number or not isFinite(Infinity);
#=> false
#isNaN() Returns true for anything that is not a number isNaN(NaN);
#=> true
#Number() Converts input into a number Number('a');
#=> NaN
#parseFloat() Converts input into a float parseFloat('3.14');
#=> 3.14
#parseInt() Converts input into a integer parseInt('3.14');
#=> 3
#String() Converts input into a string String(3.14);
#=> "3.14"

#splice(num1, num2, *args) examples

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
array1 = [ 1, 2, 3, 4, 5 ];
array1.splice( 1, 2 );
#=> [ 2, 3 ]
array1;
#=> [ 1, 4, 5 ]

array2 = [ 1, 2, 3, 4, 5 ];
array2.splice( 2, 0, 3.33, 3.67 );
#=> []
array2;
#=> [ 1, 2, 3, 3.33, 3.67, 4, 5 ]

array3 = [ 1, 2, 3, 4, 5 ];
array3.splice( 1, 3, 'two', 'three', 'four' );
#=> [ 2, 3, 4 ]
array3;
#=> [ 1, 'two', 'three',  'four', 5 ]


Lastly, an additional note for the Array Enumerable. Coming from Ruby, enumerables were always used entirely along with being told to never use for loops. While in JavsScript, it seems to be the opposite where for loops are more prevalent. For all the Rubyist who shy away from for loops and would much rather use #forEach, well for loops aren’t that bad. Compared to the #forEach method, for loops are about 95% faster.
http://jsperf.com/foreach-vs-loop

Procs and Lambdas

I am a big believer in fundamentals and foundation. In grade school I was horrific in Spanish. Being close to failing and having to repeat the previous years Spanish class, my parents sent me to summer school. I learned the fundamentals of the language and went into the following year understanding concepts which I didn't have the tools to comprehend previously.

We were told a quote early on in the semester which has stuck with me. It was along the lines of, "The problem isn't with Rails, but with your Ruby." I took away to truly understand Rails was to truly understand the fundaments and the foundation that Rails was built on.

Before diving into Proc and Lambdas which I saw as one of those fundamentals/building blocks of the Ruby language, we must go over what a Block is first.

Blocks

A block is a block of code or a code block, thus the name block. A list of instructions for your code to follow. Blocks can be identified by do...end or { }. There is a saying in Ruby land that everything in Ruby is an object, however that does not apply here. A block is not an object! Which brings us to procs and lambdas.

Procs

Proc, stands for procedure, is a block of code which is an object. This means procs can be passed through in method arguments, be something a method returns and have methods called upon them.

Creating a proc
1
2
3
4
5
square = Proc.new{ |x| x**2 }

square = Proc.new do |x|
  x**2
end

Up until now we mostly been using blocks in enumerables. Procs can take the place of blocks in enumerables.

Using a proc in an enumerable
1
2
[ 1, 2, 3, 5, 7 ].map(&square)
 => [1, 4, 9, 25, 49]

But lets say you don’t want to just pass in 1 value. Using an iterator now seems to not be the right tool for the job. There is the call method.

Call method
1
2
3
4
5
[ 15 ].map(&square)
 => [225]

 square.call( 15 )
 => 225

Another benefit procs over blocks is that they can be returned.

Proc as a return
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
class Player
  attr_accessor :coins
  def initialize
    @coins = 1000
  end
end

class Team
  attr_accessor :status
  def result
    if status
      Proc.new{ |p| p.coins += 150 }
    else
      Proc.new{ |p| p.coins -= 100 }
    end
  end
end

player1 = Player.new
player2 = Player.new
team = Team.new
team.status = true
proc = team.result

[ player1, player2 ].each(&proc)
=> [#<Player:0x007f9682936fa0 @coins=1150>, #<Player:0x007f968204d1a0 @coins=1150>]

player1.coins
=> 1150

Lambda

A lambda is also a block of code which is an object. This is because a lambda is apart of the Proc class.

Creating a lambda
1
2
3
4
5
6
7
woofs = lambda{ |x| "Woof!"*x }

woofs = lambda do |x|
  "Woof!"*x
end

=> <Proc:0x007f9683183dc0@(irb):152 (lambda)>

Procs vs Lambdas

1 - Procs and lambdas treat arguments differently. Procs do not check for the correct number or arguments while lambdas do.

Argument validation
1
2
3
4
5
6
hello = Proc.new{ |name| "Hello #{name}!" }
goodbye = lambda{ |name| "Good-bye #{name}!" }
hello.call
=> "Hello !"
goodbye.call
=> ArgumentError: wrong number of arguments (0 for 1)

2 - Proc and lambdas treat returns differently. A return inside a proc will be treated as a return for the entire method which it is inside, while a return inside a lambda will only be treated as the return for inside the lambda.

Returns
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
def proc_return
  proc = Proc.new do
    return "Hi from inside the proc!"
    puts "Do you see me?"
  end
  puts proc.call
  puts "Does this even show up?"
end

proc_return
 => "Hi from inside the proc!"

def lambda_return
  lambda = lambda do
    return "Hi from inside the lambda"
    puts "Do you see me?"
  end
  puts lambda.call
  puts "Does this even show up?"
end

lambda_return
Hi from inside the lambda
Does this even show up?
 => nil

&

& Clarification
1
2
3
4
sym = :upcase
[ 'a', 'b', 'c' ].map( &:upcase )
[ 'a', 'b', 'c' ].map{ |letter| letter.send( sym ) }
=> ["A", "B", "C"]

Additional Examples

Examples
1
2
3
4
5
6
7
8
animal_sounds = {
  'cat' => lambda{ |x| "Meow"*x},
  'dog' => lambda{ |x| "Woof"*x},
  'pig' => lambda{ |x| "Oink"*x},
  'bird' => lambda{ |x| "Kakaw"*x}
}
animal_sounds['bird'].call(2)
=> "KakawKakaw"

A Declarative Languages and Its Logical Processing Order

After two intense weeks at Flatiron School learning Ruby, we’ve moved onto SQL, a totally different langauge. Where Ruby is an object oriented programming language used in web development, SQL is a declarative language designed to manage and query databases.

The transition for me was very tough going from Ruby to SQL. Ruby being a very literal language where it reacts to everything I type typically the way I would expect. Not to say I don’t run into errors, but with tools like Pry and RSpec, debugging is managable. While this do that. For each element do this. The Ruby flow control made sense.

Now for SQL, I read it like any other language I encountered, from beginning to end, top to bottom. It made sense in the beginning, but started to not make sense when I got introduced to aggregate functions. Using a ‘COUNT’ with a ‘WHERE’ created errors which is where I learned to implement ‘HAVING’. Essentially serving the same purpose as ‘WHERE’ for the query I was making, but one was necessary for aggregate functions. This sparked my curiosity and I asked myself, do I really know what is happening here?

My answer. No. I didn’t really know what was happening behind the scenes and how my queries were being compiled. So I posed the question. If reading the query from beginning to end is not correct, then there must be some sort of order of opperation that SQL follows in reading syntax. But the answer I found was very unsatisfying. SQL is not like any language that I have encountered. SQL is a declarative language. Declarative language syntax is describing what the program should return rather than how this task should be accomplished. In simple terms, you tell SQL what you want and SQL will find a way to get it for you on through its own methods.

But there must be still rules like how I have to use ‘HAVING’ instead of ‘WHILE’!! Well, there is something that we can use in fact, for ‘SELECT’ statements at least. ‘Logical Processing Order’ determines the order of which objects are defined and made available to other sections of the ‘SELECT’ statement.

    Logical Processing Order
  1. FROM
  2. ON
  3. JOIN
  4. WHERE
  5. GROUP BY
  6. WITH CUBE or WITH ROLLUP
  7. HAVING
  8. SELECT
  9. DISTINCT
  10. ORDER BY
  11. TOP (LIMIT)

Using the ‘Logical Processing Order’ for ‘SELECT’ statements, I was able to break down the task of creating ‘SELECT’ statements into more managable steps.

Step #1 - Processes 1-3, what tables will I need to join for me to have all the information I need.

Step #2 - Processes 4-7, are there aggregate functions I need to account? If so, then I know I will need a ‘GROUP BY’, and if there is conditional logic to account for then I will need to use ‘HAVING’ instead of ‘WHERE’.

Step #3 - Process 8, what variables do I want in my ‘SELECT’ statement and do I want to rename any with ‘AS’?

Step #4 - Processes 9-11, am I looking for the query to output in a specific order or by a limit?

Knowing the control flow and asking the right questions.