Update: I include C++11 new function initializer_list for C++ example and also I correct the C++ code because it was WRONG

So after filtering, sometimes we want to do something with our data set, namely sorting. Actually filtering and sorting is one of the most recurring operation on doing data analysis. And that recurring operation need one thing in common Functional Interface which you need some, again, Predicate.

So this is our problem domain: We have a data set having list of persons which these fields:

  • First Name
  • Last Name

And we want to sort those data.

Let's do it in the most popular language ever! #Java in nice-clean OOP way and immutable as possible. First we need to define a class.

public final class Person {
  private final String firstName;
  private final String lastName;

  public Person( final String firstName_,
                 final String lastName_ )
  {
    firstName = firstName_;
    lastName  = lastName_;
  }

  public String getFirstName()
  {
    return firstName;
  }

  public String getLastName()
  {
    return lastName;
  }

  // a nice method to return object as string
  public String toString() {
    return String.format("{:firstName %s :lastName %s}",
      firstName, lastName);
  }
}

final everywhere....

So let's declare a Person array and sort'em all

ArrayList<Person> people = new ArrayList();
people.add(new Person("Banu", "Melody"));
people.add(new Person("Linggar", "Primahastoko"));
people.add(new Person("Bocah", "Miring"));

final ArrayList<Person> sortedPeople = Collections.sort (people,
  new Comparator<Person>() {
      public int compare(Person left, Person right) {
        final int compareFirst = 
          left.getFirstName().compareTo(right.getFirstName());
        if (compareFirst == 0) {
          return left.getLastName().compareTo(right.getLastName());
        }
        else {
          return compareFirst;
        }
      }
  });

Okay, that's simple enough. So let's do it to the most devilized language by Java person, #C++.

struct Person {
  std::string firstName;
  std::string lastName;

  // constructor
  inline Person(const std::string &firstName_,
      const std::string &lastName_) : firstName(firstName_),
  lastName(lastName_) {}
};

Whaat? No getter? Relax... C++ have no Bean Spec to be idiomatic. Let's sort'em all. This is the compilable version of the source code

#include <iostream>
#include <string>
#include <algorithm>
#include <vector>

// constructor
struct Person {
  std::string firstName;
  std::string lastName;

  inline Person(const std::string &firstName_,
      const std::string &lastName_) : firstName(firstName_),
  lastName(lastName_) {}
};

// predicates
inline bool personByName (const Person &left, const Person &right)  {
  const bool firstComp = left.firstName.compare(right.firstName) < 0;
  if (firstComp == 0) {
    return left.lastName.compare(right.lastName) < 0;
  }
  else {
    return firstComp;
  }
}   

// nice output
inline std::ostream &operator << (std::ostream &stream, const Person &p) {
  stream << "{:first-name \"" << p.firstName << 
    "\" :last-name \"" << p.lastName << "\"}";
  return stream;
}

// function to do some printing
void printout (const Person &p) {
  std::cout << p << std::endl;
}

int main (int argc, char **argv ) {
  std::vector<Person> people;
  people.push_back(Person("Banu", "Melody"));
  people.push_back(Person("Linggar", "Primahastoko"));
  people.push_back(Person("Bocah", "Miring"));

  std::sort(people.begin(), people.end(), personByName);
  std::for_each(people.begin(), people.end(), printout);

  return 0;
}

Weird, it should be longer... it's C++ for goodness sake! Well, if Java can use Collections.sort ande compareTo why can't we use STL's std::sort and std::for_each?

But that's is old C++ standard, we live in 2013, so why don't we use some modern C++ idiom by applying std::initializer_list and lambda support.

#include <iostream>
#include <string>
#include <algorithm>
#include <vector>

struct Person {
  std::string firstName;
  std::string lastName;

  inline Person(const std::string &firstName_,
      const std::string &lastName_) : firstName(firstName_),
  lastName(lastName_) {}
};

inline bool personByName (const Person &left, const Person &right)  {
  const bool firstComp = left.firstName.compare(right.firstName) < 0;
  if (firstComp == 0) {
    return left.lastName.compare(right.lastName) < 0;
  }
  else {
    return firstComp;
  }
}   

inline std::ostream &operator << (std::ostream &stream, const Person &p) {
  stream << "{:first-name \"" << p.firstName << 
    "\" :last-name \"" << p.lastName << "\"}";
  return stream;
}


int main (int argc, char **argv ) {
  std::vector<Person> people = std::initializer_list(
    Person("Banu", "Melody"), 
    Person("Linggar", "Primahastoko"), 
    Person("Bocah", "Miring"));

  std::sort(people.begin(), people.end(), personByName);

  // print using lambda
  std::for_each(people.begin(), people.end(), 
    [] (const Person &p) { std::cout << p << std::endl});

  return 0;
}

Okay, enough about those two fighting-for-nothing-usable languages. There's new kid in the block named #Scala. It still smells like Java, so let's give it a try.

case class Person (firstName: String, lastName: String)

val people = Vector(
  Person("Banu", "Melody"), Person("Linggar", "Primahastoko"),
  Person("Bocah", "Miring"))

def firstNameThenLastName(p1: Person, p2:Person) = {
  if (p1.firstName != p2.firstName)
    p1.firstName < p2.firstName
  else
    p2.lastName < p2.lastName
}

val sortedPeople = people sortWith firstNameThenLastName

Easy enough. Now, for completeness sake, I'll include #Clojure. It's unfair to include clojure in this comparison, it's not even OOP. But let's take a look.

(def people 
  [{:first-name "Banu" :last-name "Melody"}
   {:first-name "Linggar" :last-name "Primahastoko"}
   {:first-name "Bocah" :last-name "Miring"}])

(sort-by (juxt :first-name :last-name) people)

So which one do you like?