AdSense

Saturday, September 19, 2015

Scala note 3: OOP (TweetSet)

Week 3 class focuses on classes and objects in Scala. The OOP concepts are similar to that in Java. However, Scala uses traits instead of interface in Java to serve similar functions.

One feature in Scala that I have never met in Java is lazy val. The difference between val and lazy val is that the later will only be executed at the first time it is accessed. Lazy val is executed once and only once. This means next time the lazy val is called, it will return the same value. Details can be found here and here.

Moreover, def defines a function and every time the function is called, it creates new function. val defines a value, it returns a value that is evaluated from a function. See this post for more details.

The homework asks us to implement an abstract class called TweetSet. It should be implemented as a binary tree structure and contains two concrete subclass Empty and NonEmpty. I am not going to put the whole assignment here due to the length, but you can always go here for the problem.

package objsets

import common._
import TweetReader._

/**
 * A class to represent tweets.
 */
class Tweet(val user: String, val text: String, val retweets: Int) {
  def moreRetweets(that: Tweet) : Tweet =
    if(this.retweets >= that.retweets) this
    else that
  override def toString: String =
    "User: " + user + "\n" +
    "Text: " + text + " [" + retweets + "]"
}

/**
 * This represents a set of objects of type `Tweet` in the form of a binary search
 * tree. Every branch in the tree has two children (two `TweetSet`s). There is an
 * invariant which always holds: for every branch `b`, all elements in the left
 * subtree are smaller than the tweet at `b`. The elements in the right subtree are
 * larger.
 *
 * Note that the above structure requires us to be able to compare two tweets (we
 * need to be able to say which of two tweets is larger, or if they are equal). In
 * this implementation, the equality / order of tweets is based on the tweet's text
 * (see `def incl`). Hence, a `TweetSet` could not contain two tweets with the same
 * text from different users.
 *
 *
 * The advantage of representing sets as binary search trees is that the elements
 * of the set can be found quickly. If you want to learn more you can take a look
 * at the Wikipedia page [1], but this is not necessary in order to solve this
 * assignment.
 *
 * [1] http://en.wikipedia.org/wiki/Binary_search_tree
 */
abstract class TweetSet {

  /**
   * This method takes a predicate and returns a subset of all the elements
   * in the original set for which the predicate is true.
   *
   * Question: Can we implment this method here, or should it remain abstract
   * and be implemented in the subclasses?
   */
  def filter(p: Tweet => Boolean): TweetSet = filterAcc(p, new Empty)

  /**
   * This is a helper method for `filter` that propagetes the accumulated tweets.
   */
  def filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet

  /**
   * Returns a new `TweetSet` that is the union of `TweetSet`s `this` and `that`.
   *
   * Question: Should we implment this method here, or should it remain abstract
   * and be implemented in the subclasses?
   */
   def union(that: TweetSet): TweetSet 

  /**
   * Returns the tweet from this set which has the greatest retweet count.
   *
   * Calling `mostRetweeted` on an empty set should throw an exception of
   * type `java.util.NoSuchElementException`.
   *
   * Question: Should we implment this method here, or should it remain abstract
   * and be implemented in the subclasses?
   */
  def mostRetweeted: Tweet

  /**
   * Returns a list containing all tweets of this set, sorted by retweet count
   * in descending order. In other words, the head of the resulting list should
   * have the highest retweet count.
   *
   * Hint: the method `remove` on TweetSet will be very useful.
   * Question: Should we implment this method here, or should it remain abstract
   * and be implemented in the subclasses?
   */
  def descendingByRetweet: TweetList


  /**
   * The following methods are already implemented
   */

  /**
   * Returns a new `TweetSet` which contains all elements of this set, and the
   * the new element `tweet` in case it does not already exist in this set.
   *
   * If `this.contains(tweet)`, the current set is returned.
   */
  def incl(tweet: Tweet): TweetSet

  /**
   * Returns a new `TweetSet` which excludes `tweet`.
   */
  def remove(tweet: Tweet): TweetSet

  /**
   * Tests if `tweet` exists in this `TweetSet`.
   */
  def contains(tweet: Tweet): Boolean

  /**
   * This method takes a function and applies it to every element in the set.
   */
  def foreach(f: Tweet => Unit): Unit
  
  /**
   * if the set is empty
   */
  def isEmpty: Boolean
}

class Empty extends TweetSet {

  def filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet = acc
  
  def union(that: TweetSet): TweetSet = that
  
  def mostRetweeted: Tweet = throw new NoSuchElementException("Empty TweetSet")
 
  def isEmpty: Boolean = true
  
  def descendingByRetweet: TweetList = Nil

  /**
   * The following methods are already implemented
   */

  def contains(tweet: Tweet): Boolean = false

  def incl(tweet: Tweet): TweetSet = new NonEmpty(tweet, new Empty, new Empty)

  def remove(tweet: Tweet): TweetSet = this

  def foreach(f: Tweet => Unit): Unit = ()
}

class NonEmpty(elem: Tweet, left: TweetSet, right: TweetSet) extends TweetSet {

  def filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet = {
    if (p(this.elem)) 
      left.filterAcc(p, right.filterAcc(p, acc.incl(this.elem)))
    else
     left.filterAcc(p, right.filterAcc(p, acc))  
  }
  def union(that: TweetSet): TweetSet =
    (left.union(right)).union(that).incl(elem)
  
  def isEmpty: Boolean = false
   
  def mostRetweeted: Tweet = 
    if (left.isEmpty && right.isEmpty) elem
    else if (left.isEmpty) elem.moreRetweets(right.mostRetweeted)
    else if (right.isEmpty) elem.moreRetweets(left.mostRetweeted)
    else elem.moreRetweets(left.mostRetweeted).moreRetweets(right.mostRetweeted)
    
 def descendingByRetweet: TweetList = 
   new Cons(mostRetweeted, remove(mostRetweeted).descendingByRetweet)

  /**
   * The following methods are already implemented
   */

  def contains(x: Tweet): Boolean =
    if (x.text < elem.text) left.contains(x)
    else if (elem.text < x.text) right.contains(x)
    else true

  def incl(x: Tweet): TweetSet = {
    if (x.text < elem.text) new NonEmpty(elem, left.incl(x), right)
    else if (elem.text < x.text) new NonEmpty(elem, left, right.incl(x))
    else this
  }

  def remove(tw: Tweet): TweetSet =
    if (tw.text < elem.text) new NonEmpty(elem, left.remove(tw), right)
    else if (elem.text < tw.text) new NonEmpty(elem, left, right.remove(tw))
    else left.union(right)

  def foreach(f: Tweet => Unit): Unit = {
    f(elem)
    left.foreach(f)
    right.foreach(f)
  }
}

trait TweetList {
  def head: Tweet
  def tail: TweetList
  def isEmpty: Boolean
  def foreach(f: Tweet => Unit): Unit =
    if (!isEmpty) {
      f(head)
      tail.foreach(f)
    }
}

object Nil extends TweetList {
  def head = throw new java.util.NoSuchElementException("head of EmptyList")
  def tail = throw new java.util.NoSuchElementException("tail of EmptyList")
  def isEmpty = true
}

class Cons(val head: Tweet, val tail: TweetList) extends TweetList {
  def isEmpty = false
}


object GoogleVsApple {
  val google = List("android", "Android", "galaxy", "Galaxy", "nexus", "Nexus")
  val apple = List("ios", "iOS", "iphone", "iPhone", "ipad", "iPad")

  //TweetReader.allTweets foreach println
  lazy val googleTweets: TweetSet = TweetReader.allTweets.filter(tweet => google.exists(keyWord => tweet.text.contains(keyWord)))
  lazy val appleTweets: TweetSet = TweetReader.allTweets.filter(tweet => apple.exists(keyWord => tweet.text.contains(keyWord)))


  /**
   * A list of all tweets mentioning a keyword from either apple or google,
   * sorted by the number of retweets.
   */
  lazy val trending: TweetList = googleTweets.union(appleTweets).descendingByRetweet
}

object Main extends App {
  // Print the trending tweets
 GoogleVsApple.trending foreach println
}

I only include the part that we need to implement here. Due to the functional nature, it is fairly easy to understand. However, I do realize that due to intensive recursion, the program is slow, like really slow if we test for all tweets included in the test program. Or probably just my bad implementation?

The whole assignment can be found on git.

Thursday, September 10, 2015

B-Tree Java implementation

Two days of coding. One afternoon to build a tree, three nights to destroy the tree in different ways, I finally make the code.

Sort of...

The code works for M >= 4, where M is the number of maximum key-value pairs in one node (In fact, this number can never be reached because the node will be split into two once this number is reached.

For rules on how B-Tree works, refer to this post. I may update this blog when I fix the deletion issue with M = 3 (probably rewrite the code to make it cleaner). Moreover, it turns out Cassandra has a B-Tree implementation. It's a little bit to complicated for me (plus I couldn't find its deletion implementation), but it's interesting to take a look. Check here.


package bTree;


/**
 * M: maximum degree/number of key-value pairs in a node
 * HT:height of the B-tree
 * N: number of key-value pairs in the tree
 * @author shirleyyoung
 *
 * @param 
 * @param 
 */
public class BTree <Key extends Comparable<Key>, Value>{
	private int M;
	private Node root;
	private int HT;
	private int N;
	
	/******************************************************
	 * The structure to store the key-value pairs
	 * @author shirleyyoung
	 *
	 ******************************************************/
	private class Entry <Key extends Comparable<Key>, Value> implements Comparable{
		private Comparable key;
		private Object value;
		public Entry(Comparable key, Object value){
			this.key = key;
			this.value = value;
		}
		
		public int compareTo(Entry e) {
			return key.compareTo(e.key);
		}
		public String toString(){
			return "(" + key.toString() + ", " + value.toString() + ")";
		}
	}
	
	
	/***************************************************************
	 * tree node class
	 * Each node is a list of Entry objects
	 * Entry list is used for all key - value pairs stored in the node
	 * index: the current number of key-value pairs,
	 * as well as the index where next key-value pair will be added
	 * since it's 0 index, the node contains m + 1 key - value pairs
	 * entryList: the entryList
	 * children: children list of the node, each node may have at most
	 * M + 1 children
	 * @author shirleyyoung
	 *
	 ***************************************************************/
	private class Node  indexToAdd; i--)
				entryList[i] = entryList[i - 1];
			entryList[indexToAdd] = e;
			index++;
		}
		
		public String toString(){
			String s = "";
			for (int i = 0; i < index; i++){
				s += entryList[i].toString() + ", ";
				
			}
			s = s.substring(0, s.length() - 2);
			s += String.format("\nindex: %d\n", index);
			return s;
		}
	}

	/*******************************************************
	 * constructor
	 * @param M
	********************************************************/
	public BTree(){
		M = 4;
		HT = 0;
		N = 0;
		root = new Node();
	}
	public BTree(int M){
		this();
		this.M = M;
		root = new Node();
	}
	
	/********************************************************
	 * search for a value given the key
	 * @param key
	 * @return
	 *******************************************************/
	public Object get(Comparable key){
		Entry found = search(root, key, HT);
		if (found == null){
			System.out.println("No such key!");
			return null;
		}
		else return found.value;
	}
	private Entry search(Node x, Comparable key, int ht){
		if (x == null)
			return null;
		Entry[] entryList = x.entryList;
		if(ht == 0){//leaf node
			for(int j = 0; j < x.index; j++){
				if(key.equals(entryList[j].key))
					return entryList[j];
			}
		} else{
			for(int j = 0; j < x.index; j++){
				if (key.equals(entryList[j].key))
					return entryList[j];
				else if(j == 0 && key.compareTo(entryList[j].key) < 0)
					return search(x.children[j], key, ht - 1);
				else if(j == x.index - 1|| key.compareTo(entryList[j + 1].key) < 0)
					return search(x.children[j + 1], key, ht - 1);
			}
		}
		return null;
	}
	
	
	/*******************************************************
	 * Insertion
	 * @param key
	 * @param value
	 *******************************************************/
	public void insert(Comparable key, Object value){
		Entry exists = search(root, key, HT);
		if(exists != null){
			exists.value = value;
			System.out.println("Key already exists, modify the value to the input value.");
			return;
		}
		Node newRoot = insert(root, key, value, HT);
		N++;
		if(newRoot == null) return;
		root = newRoot;
		HT++;
	}
	private Node insert(Node curr, Comparable key, Object value, int ht){
		int indexToInsert;
		if(ht == 0){//leaf nodes level
			//find the correct place to insert the value			
			for(indexToInsert = 0; indexToInsert < curr.index; indexToInsert++){
				if(key.compareTo(curr.entryList[indexToInsert].key) < 0) break;
			}
			//shift the larger nodes right
			curr.add(new Entry(key, value), indexToInsert);
			
			//the key value pair is added to the existing node, no new node is inserted, return null
			if(curr.index < M) return null;
			return split(curr);
		}else {
			for(indexToInsert = 0; indexToInsert < curr.index; indexToInsert++){
				if (indexToInsert == 0 && key.compareTo(curr.entryList[indexToInsert].key) < 0) break;			
				else if((indexToInsert == curr.index - 1) || key.compareTo(curr.entryList[indexToInsert + 1].key) < 0){
					//children[j].next, j++
					indexToInsert += 1;
					break;
				}
			}
			Node u = insert(curr.children[indexToInsert], key, value, ht - 1);
			if(u == null) return null;
			return combine(curr, u);
		}
	}
	/*********************************************************
	 * split the node if it reaches maximum degree
	 * choose middle node as the new root 
	 * e.g., if M = 4 or 5, choose entryList[2] as new root
	 * @param curr
	 * @return
	 *********************************************************/
	private Node split(Node curr){
		Node newRoot = new Node();
		newRoot.entryList[0] = curr.entryList[M/2];
		newRoot.index++;
		Node right = new Node();
		int j = 0, i = M/2 + 1;
		while(j < M && i < M){
			right.entryList[j] = curr.entryList[i];
			right.children[j++] = curr.children[i++];
		}
		right.children[j] = curr.children[i];
		right.index = j;
		curr.index = M/2;
		newRoot.children[0] = curr;
		newRoot.children[1] = right;
		return newRoot;
	}
	/****************************************************
	 * combine two nodes when total elements 
	 * are less than M
	 * split the node if the entry list of the 
	 * combined node reaches M
	 * @param left
	 * @param right
	 * @return
	 ****************************************************/
	private Node combine(Node left, Node right){
		int j = 0;
		int total = left.index + right.index;
		while (left.index < total){
			left.entryList[left.index] = right.entryList[j];
			left.children[left.index++] = right.children[j++];
		}
		left.children[left.index] = right.children[j];
		right.children = null;
		right = null;
		if (left.index < M) {return null;}
		else return split(left);
	}
	
	/****************************************************
	 * Deletion
	 * @param key
	 * @return
	 ****************************************************/
	public Object delete(Comparable key){
		Entry toDelete = search(root, key, HT);
		if(toDelete == null) {
			System.out.println("No such key!");
			return null;
		}
		N--; 
		return delete(root, key, HT).value;
	}
	private Entry delete(Node n, Comparable key, int ht){
		int index = n.searchEntry(key);
		if(ht == 0){ // if leaf nodes
			if(n.entryList[index].key != key)
				return null;
			else
				return n.removeEntry(index);
		}else {
			if (key.equals(n.entryList[index].key)){ //if key is in internal node n
				//if left children has a size larger than M/2
				//replace entry that has the key to be deleted in n with the largest 
				//entry in left children, then recursively delete children entry
				//System.out.println("found index: " + index);
				Entry toDelete = n.entryList[index];
				int h = ht - 1;
				if(n.children[index].index >= M/2){ 
					Node child = n.children[index];
					while (h != 0){
						child = child.children[child.index];
						h--;
					}
					n.entryList[index] = child.entryList[child.index - 1];
					delete(n.children[index], child.entryList[child.index - 1].key, ht - 1);
				//else if right children has a size larger than M/2
				//replace entry has the key to be deleted in n with the smallest
				//entry in right children, then recursively delete children entry
				} else if (n.children[index + 1].index >= M/2){
					Node child = n.children[index + 1];
					while(h != 0){
						child = child.children[0];
						h--;
					}
					n.entryList[index] = child.entryList[0];
					delete(child, child.entryList[0].key, h);
				//case 3 will take care of the case when node n has too few entries to be moved
				} else {
					n = moveEntryDown(n.children[index], n, index, n.children[index + 1]);
					if (ht == HT && root.index == 0){
						root = n;
						HT--;
						ht--;
					}
					delete(n, key, ht);
				}
				return toDelete;
			} else { // if key is not in internal node n
				//find the root of the subtree where the desired key is 
				//supposed to present
				//System.out.println("index: " + index);
				//System.out.println("children[index] has index: " + n.children[index].index);
				//Node child = n.children[index];
				//System.out.println("Largest children key: " + child.entryList[child.index - 1].key);
				if(index == (n.index - 1) && key.compareTo(n.entryList[n.index - 1].key) > 0){
					//child = n.children[index + 1];
					index += 1;
				}
				//if key is in the children
				boolean chk = key == n.children[index].entryList[n.children[index].searchEntry(key)].key;
				if (n.children[index].index < M/2 && chk){
					//case 3a, left sibling has size at least M/2
					//remove the last entry from the left sibling, put into n[index - 1]
					//add n[index - 1] to the n.children[index]
					if(index > 0 && n.children[index - 1].index >= M/2){
						Node helper = n.children[index - 1];
						n.children[index].add(n.entryList[index - 1], 0);
						n.entryList[index - 1] = helper.entryList[helper.index - 1];
						helper.removeEntry(helper.index - 1);
					//case 3a, right sibling has size at least M/2
					} else if (index < n.index && n.children[index + 1].index >= M/2){
						Node helper = n.children[index + 1];
						n.children[index].add(n.entryList[index], n.children[index].index);
						n.entryList[index] = helper.entryList[0];
						helper.removeEntry(0);
					//case 3b, merge two nodes
					} else {
						Node mergeChild = n.children[index];
						if(index == n.index)
							n = moveEntryDown(n.children[index - 1], n, index - 1, mergeChild);
						else n = moveEntryDown(mergeChild, n, index, n.children[index + 1]);
						if (ht == HT && root.index == 0){
							root = n;
							HT--;
							ht--;
						}
						return delete(n, key, ht);
					}
				}
				if (index == n.index - 1 && key.compareTo(n.entryList[index].key) > 0)
					return delete(n.children[index + 1], key, ht - 1);
				else return delete(n.children[index], key, ht - 1);
			}
		}
	}
	/**
	 * combine left and right children and move the entry (parent[index]) down
	 * to serve as median node
	 * only be called when both left and right has size < M/2
	 * and parent has size >= M/2
	 * @param left
	 * @param parent
	 * @param index
	 * @param right
	 */
	private Node moveEntryDown(Node left, Node parent, int index, Node right){
		left.add(parent.entryList[index], left.index);
		parent.removeEntry(index);
		combine(left, right);
		if (parent.index == 0) 
			parent = left;
		else parent.children[index] = left;
		return parent;
	}
	
	public String toString(){
		return toString(root, HT) + "\n";
	}
	private String toString(Node n, int ht){
		String s = "";
		if(ht == 0){
			for(int i = 0; i < n.index; i++)
				s += i + ": " + n.entryList[i].toString() +  "\n";
		} else{
			for(int i = 0; i < n.index; i++){
				s += i + ": " + n.entryList[i].toString() + "\nChildren " + i + ": \n";
				s += toString(n.children[i], ht - 1) + "\n";
			}
			s += toString(n.children[n.index], ht - 1);
		}
		return s;
	}
	
	
	public int size(){
		return N;
	}
	public int height(){
		return HT + 1;
	}
}

Check my git for test code.

Monday, September 7, 2015

Scala note 2: Functional Sets

Mathematically, we call the function which takes an integer as argument and which returns a boolean indicating whether the given integer belongs to a set, the characteristic function of the set. For example, we can characterize the set of negative integers by the characteristic function (x: Int) => x < 0.
Therefore, we choose to represent a set by its characterisitc function and define a type alias for this representation:
type Set = Int => Boolean
Using this representation, we define a function that tests for the presence of a value in a set:
def contains(s: Set, elem: Int): Boolean = s(elem)

2.1 Basic Functions on Sets

Let’s start by implementing basic functions on sets.
  1. Define a function which creates a singleton set from one integer value: the set represents the set of the one given element. Its signature is as follows:
    def singletonSet(elem: Int): Set
    Now that we have a way to create singleton sets, we want to define a function that allow us to build bigger sets from smaller ones.
  2. Define the functions union, intersect, and diff, which takes two sets, and return, respectively, their union, intersection and differences.diff(s, t) returns a set which contains all the elements of the set s that are not in the set t. These functions have the following signatures:
    def union(s: Set, t: Set): Set
    def intersect(s: Set, t: Set): Set
    def diff(s: Set, t: Set): Set
  3. Define the function filter which selects only the elements of a set that are accepted by a given predicate p. The filtered elements are returned as a new set. The signature of filter is as follows:
    def filter(s: Set, p: Int => Boolean): Set

2.2 Queries and Transformations on Sets

In this part, we are interested in functions used to make requests on elements of a set. The first function tests whether a given predicate is true for all elements of the set. This forall function has the following signature:
def forall(s: Set, p: Int => Boolean): Boolean
Note that there is no direct way to find which elements are in a set. contains only allows to know whether a given element is included. Thus, if we wish to do something to all elements of a set, then we have to iterate over all integers, testing each time whether it is included in the set, and if so, to do something with it. Here, we consider that an integer x has the property -1000 <= x <= 1000 in order to limit the search space.
  1. Implement forall using linear recursion. For this, use a helper function nested in forall. Its structure is as follows (replace the ???):
    def forall(s: Set, p: Int => Boolean): Boolean = {
     def iter(a: Int): Boolean = {
       if (???) ???
       else if (???) ???
       else iter(???)
     }
     iter(???)
    }
  2. Using forall, implement a function exists which tests whether a set contains at least one element for which the given predicate is true. Note that the functions forall and exists behave like the universal and existential quantifiers of first-order logic.
    def exists(s: Set, p: Int => Boolean): Boolean
  3. Finally, write a function map which transforms a given set into another one by applying to each of its elements the given function. map has the following signature:
    def map(s: Set, f: Int => Int): Set


Coursera Scala course week 2 homework. The original question can be found here.

The question asks as two define an object Set, which has a characteristic function that projects an integer to a boolean.

1. define Singleton
This question requires us to create a set with one integer, i.e., given an integer, projects it to a boolean to claim the set contains the integer:

def singletonSet(elem: Int): Set = (x: Int) => x == elem

This means projects an integer x to if x equals given parameter elem. It can also be considered as given any integer, if x equals elem, then set contains x, which defines the singleton set that it only contains elem.

2. define Union, Intersect and Difference

  def union(s: Set, t: Set): Set = (x: Int) => s(x) || t(x)
  def intersect(s: Set, t: Set): Set = (x: Int) => s(x) && t(x)
  def diff(s: Set, t: Set): Set = (x: Int) => s(x) && !t(x)

s(x) indicates contains. Thus, for union, it means either for any x, if it satisfies the condition that either s contains x or t contains x, then x is in union. For intersect, the condition becomes both s and t should contains x. For difference, it means s should contain x but t should not.

3. define filter

def filter(s: Set, p: Int => Boolean): Set = (x: Int) => s(x) && p(x)

filter is a set that for any x in filter, it should satisfies that s contains x and x satisfies predicate p.

4. forall (∀ )

val bound = 1000

  def forall(s: Set, p: Int => Boolean): Boolean = {
    def iter(a: Int): Boolean = {
      if (a > bound) true
      else if (s(a) && !p(a)) false
      else iter(a+1)
    }
    iter(-bound)
  }

This is nothing special. Starts from -bound, if any a in s doesn't satisfy p, then return false. Iterate until bound, then return true.

5. exists(∃ )

def exists(s: Set, p: Int => Boolean): Boolean = !forall(s, x => !p(x))

This one is tricky. The solution means not all elements in s satisfies !p, which in turn indicates there is at least one element in s satisfies p.

6. map

def map(s: Set, f: Int => Int): Set = (y: Int) => exists(s, x => f(x) == y)

This is similar as how we define a singleton set: For any y, if there exists an element x in s that satisfies the condition f(x) equals y, then y is in new Set map.


Source on git.

Wednesday, August 26, 2015

Scala note 1: Pascal’s Triangle, Parentheses Balancing and Counting Change

I decided to take a look on Scala, so that next time I read a source code, at least I know what I am reading.

I choose Coursera's Functional Programming Principles in Scala as my reference (I do wish they open the class again, however, the same time when they open the class last year, I was fighting with Java ðŸ˜ž.)

First week's class are basics. Two concepts need to be remember:

Call by value: evaluates function arguments before calling the functionCall by name: evaluates the function first, and then evaluate the arguments if needed
Scala usually do call by value, but we can also do call by name by adding x: => Type to the parameter. 
All three exercise problems are about recursions. The algorithms are easy since those are problems we see all the time. 

Pascal's Triangle
The numbers at the edge of the triangle are all 1, and each number inside the triangle is the sum of the two numbers above it. Write a function that computes the elements of Pascal’s triangle by means of a recursive process.Do this exercise by implementing the pascal function in Main.scala, which takes a column c and a row r, counting from 0 and returns the number at that spot in the triangle. For example, pascal(0,2)=1, pascal(1,2)=2 and pascal(1,3)=3.def pascal(c: Int, r: Int): Int

def pascal(c: Int, r: Int): Int = {
    if  (c == 0 || c == r || r == 0)  1
    else
      pascal(c - 1, r - 1) + pascal(c, r - 1)
  }

Sort of short...


Parentheses Balancing
Write a recursive function which verifies the balancing of parentheses in a string, which we represent as a List[Char] not a String. For example, the function should return true for the following strings:
  • (if (zero? x) max (/ 1 x))
  • I told him (that it’s not (yet) done). (But he wasn’t listening)
The function should return false for the following strings:
  • :-)
  • ())(
The last example shows that it’s not enough to verify that a string contains the same number of opening and closing parentheses.Do this exercise by implementing the balance function in Main.scala. Its signature is as follows:def balance(chars: List[Char]): Boolean
def balance(chars: List[Char]): Boolean = {
    def balance(chars: List[Char], left: Int): Boolean ={
      if(chars.isEmpty) left == 0
      else
        if (chars.head == ')') {left > 0 && balance(chars.tail, left - 1)}
        else if (chars.head == '(') {balance(chars.tail, left + 1)}
        else {balance(chars.tail, left)} 
    }
    balance(chars, 0)
  }

Basically, we count the left parenthesis ("(") . Each time there is a "(", we increment left. If there is a ")" and if left >0, then it is imbalanced, otherwise decrease left and check the substring. 

Counting Change
Write a recursive function that counts how many different ways you can make change for an amount, given a list of coin denominations. For example, there are 3 ways to give change for 4 if you have coins with denomiation 1 and 2: 1+1+1+1, 1+1+2, 2+2.Do this exercise by implementing the countChange function in Main.scala. This function takes an amount to change, and a list of unique denominations for the coins. Its signature is as follows:def countChange(money: Int, coins: List[Int]): Int


def countChange(money: Int, coins: List[Int]): Int = {
    def countChange(money:Int, coins: List[Int], count:Int): Int = {
      if (money < 0) count
      else
        if (coins.isEmpty) 
          if (money == 0) count + 1 else count
        else
          countChange(money - coins.head, coins, count) + countChange(money, coins.tail, count)
    }
    countChange(money, coins, 0)
  }

To count all possibilities, we need to iterate all denominations in coins. Using recursion, it is the count of using coins[0] plus the count of not using coins[0], and recursively check all the denominations.


Source on git. 

Sunday, August 16, 2015

Apache Kafka Java API example

I've just started learning Apache Kafka, and I realize there are not much documentation and examples on the project. So I decide to prepare my own notes.

Start Kafka
Kafka can be installed through source or compiled package. If you are interested in doing it via source, see this git. 

To make things easier, I choose the compiled package. Since everything is compiled, all we need to do is to start the servers. 
Kafka runs on ZooKeeper, so the first thing is to start the ZooKeeper server:
In the directory where Kafka is installed:

bin/zookeeper-server-start.sh config/zookeeper.properties

In a different window/tab, start Kafka server:

bin/kafka-server-start.sh config/server.properties

Create a topic
A topic is a category/feed name to which message are published. The producer sends message to the topic it chooses (see the following code for details), and the consumer accepts messages to the topic it wants.
In a different window/tab, create a topic (named "test"):

bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test

Create producer and consumers through Java API
If you just want to get your feet wet, follow the doc and try creating producers and consumers through command line.

Here I use Eclipse to make things easier.

First, in Eclipse, create a Maven project (refer this post for creating a Maven project in Eclipse). To include dependencies in pom.xml, open pom.xml, at the bottom click pom.xml (see the figure below), and add the following dependencies:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>Kafka</groupId>
  <artifactId>KafkaProject</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>kafkatest</name>
  <url>http://maven.apache.org</url>
  <properties>
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  
  <dependencies>
   <dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka_2.10</artifactId>
    <version>0.8.2.1</version>
    <scope>compile</scope>
    <exclusions> 
     <exclusion> 
      <artifactId>jmxri</artifactId> 
      <groupId>com.sun.jmx</groupId> 
     </exclusion> 
     <exclusion> 
      <artifactId>jms</artifactId> 
      <groupId>javax.jms</groupId> 
     </exclusion> 
     <exclusion> 
      <artifactId>jmxtools</artifactId> 
      <groupId>com.sun.jdmk</groupId> 
     </exclusion> 
    </exclusions>
   </dependency>
  </dependencies>
</project>


Be sure to include all exclusions, otherwise you will get error.

Before writing our Producer class, start a consumer in a new window/tab in terminal (in the directory where Kafka is installed):

bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic test --from-beginning

Now create a class ProducerTest (or whatever name you want).

import java.util.*;
import kafka.javaapi.producer.Producer;
import kafka.producer.KeyedMessage;
import kafka.producer.ProducerConfig;

public class ProducerTest {
 public static void main(String[] args) { 
  Properties props = new Properties();
  props.put("zk.connect", "localhost:2181"); 
  props.put("serializer.class","kafka.serializer.StringEncoder");
  props.put("metadata.broker.list", "localhost:9092");
  ProducerConfig config = new ProducerConfig(props);
  Producer<string, string> producer = new Producer<string, string>(config);
  for (long nEvents = 0; nEvents < 10; nEvents++){
   System.out.println("Creating events " + nEvents);
   long runtime = new Date().getTime();
   String msg = runtime + ", Shirley is awesome.";
   producer.send(new KeyedMessage<string, string>("test", msg));
  } 
 }
}

Now if you run the code, you will see messages showing up in the window/tab where consumer is created.

syang:kafka_2.10-0.8.2.0 syang$ bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic test --from-beginning
test
1439686893619, Shirley is awesome.
1439686893722, Shirley is awesome.
1439686893724, Shirley is awesome.
1439686893725, Shirley is awesome.
1439686893727, Shirley is awesome.
1439686893728, Shirley is awesome.
1439686893729, Shirley is awesome.
1439686893731, Shirley is awesome.
1439686893732, Shirley is awesome.
1439686893733, Shirley is awesome.


Start a producer in a new window/tab:

bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test

Create a ConsumerTest class:
The consumer class is more complicated since it involves multithreading.

public class ConsumerTest extends Thread{
 private final ConsumerConnector consumer;
 private final String topic;
 
 public ConsumerTest(String topic){
  consumer = kafka.consumer.Consumer
    .createJavaConsumerConnector(createConsumerConfig());
  this.topic = topic;
 }
 public static ConsumerConfig createConsumerConfig(){
  Properties props = new Properties();
  props.put("zookeeper.connect", "localhost:2181");
  props.put("group.id", "test_group");
  props.put("zookeeper.session.timeout.ms", "400000");
  props.put("zookeeper.sync.time.ms", "200");
  props.put("auto.commit.interval.ms", "1000");
  return new ConsumerConfig(props);
 }
 
 public void run(){
  Map<String, Integer> topicCountMap = new HashMap<String, Integer>();
  topicCountMap.put(topic, 1);
  Map<String, List<KafkaStream<byte[], byte[]>>> consumerMap = consumer.createMessageStreams(topicCountMap);
  KafkaStream<byte[],byte[]> stream = consumerMap.get(topic).get(0);
  ConsumerIterator<byte[], byte[]> it = stream.iterator();
  while (it.hasNext())
   System.out.println(new String(it.next().message()));
 } 
 public static void main(String[] args) {
  ConsumerTest consumerThread = new ConsumerTest("test");
  consumerThread.start();
 }
}


Configurations
Both Producer and Consumer class requires a Properties object (implemented as a HashTable), which set the configurations for Producer and Consumer.

Producer configurations:
zk.connect: Specifies the Zookeeper connection string in the form of hostname:port/chroot. The chroot is a base directory which is prepended to all path operations. This namespaces all Kafka znodes to allow sharing with other applications on the same zookeeper cluster.
serializer.class: Used to encode data of type T into a Kafka message.
metadata.broker.list:the producer will only use it for getting metadata(topics, partitions and replicas). The socket connection for sending the actual data will be established based on the broker information returned in the metadata. Format host1:port1, host2, port2.

Consumer configurations:
group.id: A string that uniquely identifies the group of consumer processes to which this consumer belongs(producer sends messages to all consumer groups, each consumer receive desired messages).
zookeeper.session.timeout.ms: If the consumer fails to heartbeat to ZooKeeper for this period of time it is considered dead and a rebalance will occur.
zookeeper.sync.tims.ms: How far a zookeeper follower can be behind a zookeeper lead.
auto.commit.interval.ms: the frequency in ms that the consumer offsets are committed to a zookeeper.

 References:
[1] Kafka documentation
[2] http://vulab.com/blog/?p=611
[3] http://vulab.com/blog/?p=623
[4] http://blog.csdn.net/ganglia/article/details/12651891

Saturday, August 15, 2015

Merge K sorted linked lists/arrays revisited

K sorted arrays

I got a comment on my previous post Merge K sorted arrays, and I realized that there are much easier (and shorter) solutions to solve this problem. Here is the code snippet in both Java and Python.

Java:

public static List<Integer> merged (List<int[]> arrays){
  List<Integer> mergedArrays = new ArrayList<Integer> ();
  if (arrays == null || arrays.size() == 0){
   return mergedArrays;
  }
  for (int[] array : arrays){
   for (int i : array)
    mergedArrays.add(i);
  }
  Collections.sort(mergedArrays);
  return mergedArrays;
 }

Python:


def merged(lists):
    if lists is None or len(lists) == 0:
        return None
    mergedArray = [n for array in lists for n in array]
    return sorted(mergedArray)

Yeah, you can't disagree that the Pythonic way sometimes make things too easy to believe.

Why does this work:
Since in any case, we have to traverse the whole every element in the list of arrays, the complexity is O (mn), where m is the length of the list and n is the average length of each array.  Collections.sort() implements Timsort (see here, here and here) which on average has complexity O(nlogn). The time complexity is the same as using a priority queue, but with much shorter code.


K sorted lists

This gives me a reason to rethink the merge K sorted linked lists problem.
Unfortunately, since we need to return a linked list, we cannot use any built-in sorting methods.
I rewrite the code using Python. In Python, the built-in heapq only provides sorting based on natural order. Since the queue can sort tuples based on its first element, one solution could be wrapping the elements to be sorted to tuples (priority, element). See the code for detail[1].

import heapq
from mergeAndSort.ListNode import ListNode

class PriorityQueue(object):
    def __init__(self, initial = None, key=lambda x:x):
        self.key = key
        if initial:
            self._data = [(key(item), item) for item in initial]
            heapq.heapify(self._data)
        else:
            self._data = []

    def push(self, item):
        heapq.heappush(self._data, (self.key(item), item))

    def pop(self):
        return heapq.heappop(self._data)[1]

    def __len__(self):
        return len(self._data)

    def empty(self):
        return len(self._data) == 0

class ListNode(object):
    def __init__(self, val):
        self.val = val
        self.next = None

def mergeKLists(lists):
    if lists is None or len(lists) == 0:
            return None
    pq = PriorityQueue(key=lambda x:x.val)
    for n in lists:
        if n is not None:
            pq.push(n)
    head = ListNode(-1)
    h = head
    while not pq.empty():
        n = pq.pop()
        head.next = n
        head = head.next
        if n.next is not None:
            pq.push(n.next)
    return h.next

Comparison
Based on Leetcode's compiler, this Python implementation is not faster than the Java one. I'm sure there should be better solutions, please let me know.

Reference:
[1] http://stackoverflow.com/questions/8875706/python-heapq-with-custom-compare-predicate

Saturday, August 8, 2015

Too young to figure out, too old to wait

I finally settled down in CA, got the job I like and started to work on things I want. Yet there is still one thing haunt my mind: I wish I was three years younger. I probably don't have to worry about lots of things, don't have to be so scared about making a wrong decision, and probably don't have to make so many plans that stress me out.

They say it's never too late.

I want to say "Yes, it is", but I decided to change and go with "It depends". Last year, someone told me about the CEO of a startup is three years younger than him and is better than him in both technical skills and persistence. I told him you came from a different background and there is never too late for anything. He thought I didn't understand him and I was naive.

Now I am in a similar situation hoping if I could be three years younger. I definitely don't want what he wants, but as I step into my job, things are getting clearer. However, I have just started as a new grad and I have so many things I need to learn. And life is getting more complicated as I am older. I feel suffocated sometime.

Last night, I had a long conversation with my friend. The third time he talked about an amazing personality test, I told him I wouldn't do it if it will cost me anything. It's not about I don't want to know more about myself. Sometimes I am curious about what about me that is still hidden from me. Yet I am confident that I have known enough about myself that anything I still don't know doesn't worth a penny (or I am just arrogant :) ).

The reason I brought up this is because I realize all the stress, fear, regrets and everything else came from my personality: the ultimate double-edged sword -- responsibility. This is definitely a good type of personality (in most ways), but it becomes a burden when one treats it too important, like me. I always feel responsible to my work, my family and my friends. I would avoid taking charge of things because I think the responsibility would suffocate me. Most of them don't, and I always end up well. But the fear of it haunts me and holds me back.

There is one thing I learned from the popular movie Inside out: Everything has two sides, you just have to find the balance. I guess I am still too young (?) to figure that out.

At the end of last year, I regretted that because of my mistake I lost a friend. In the next couple months, I thought I was trying to make things better, it turned out to have made things even worse. In April, he complained to my friend calling me "having negative EQ". I didn't talk to him for three months. Considering he helped me a lot when I needed most (looking for jobs), I tried to amend with him and talked to him again, only to get the angry mail "I think you are annoying, stupid and hypocritical", that did not only hurt but also made me sick. In the next couple days I kept thinking what I did wrong this time, I couldn't think any. After the grievance and emotion was gone, I realize I was not the only one who made things irreparable. Even now I am still regretful for the mistake I made. And from time to time I would think what if... It probably is because I felt so sorry about what I did and thought about the help he gave me that I was too tolerant on how he treated me. And he took it for granted. Then one day I couldn't take it anymore and things got screwed up.

That was the worst relationship experience I have ever had with a person I think overall is decent and in another case I would admire. But now when I think about it every time it makes me sick. I imagine all the time that I have an eraser, wipe everything in my mind and start all over again. Yet I don't have one, and unless there is a huge accident happen to me (please don't) I probably won't lose that part of memory, at least for a very long time. I know it started from me but if he could be less asshole to piss me off things might not be like this.

Yet I don't have a time machine nor Doraemon doraemon cat doraemon cat.  All I have is a lesson I learned after this mess. It probably is true that I learn something for every mistake I make. But I am too old to not having understood lots of things, and I don't feel I am patient enough to wait.

But God is a bitch. She doesn't give you what you want until you struggle enough and ready to give up. They say you never figure out everything. I hope when I am too old to mess everything up I understand most of the things I want. Or not?