Sort on many fields

From CodeCodex

Implementations[edit]

Java[edit]

We want to sort a Collection of Person objects based on their LastName and Firstname. First the Person class

class Person implements Comparable {
  String firstName, lastName;

  public Person(String f, String l) {
    this.firstName = f;
    this.lastName = l;
  }

  public String getFirstName() {
    return firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public String toString() {
    return "[ firstname=" + firstName + ",lastname=" + lastName + "]";
  }

  public int compareTo(Object obj) {
    Person emp = (Person) obj;
    int deptComp = firstName.compareTo(emp.getFirstName());

    return ((deptComp == 0) ? lastName.compareTo(emp.getLastName())
        : deptComp);
  }

  public boolean equals(Object obj) {
    if (!(obj instanceof Person)) {
      return false;
    }
    Person emp = (Person) obj;
    return firstName.equals(emp.getFirstName())
        && lastName.equals(emp.getLastName());
  }
}

then we need a class to implement the Comparable interface. It's in there where we put the logic behind the sorting.

import java.util.Comparator;

class PersonComparator implements Comparator{
  public int compare(Object obj1, Object obj2) {
    Person emp1 = (Person) obj1;
    Person emp2 = (Person) obj2;

    int nameComp = emp1.getLastName().compareTo(emp2.getLastName());

    return ((nameComp == 0) ?
              emp1.getFirstName().compareTo(emp2.getFirstName()) :
                nameComp);
  }
}

To test it :

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Iterator;

public class TestSort {
  public static void main(String args[]) {
    String Smith[] = { "Real", "Vincent", "Nathalie", "Christine" };
    String Simpsons[] = { "Bart", "Lisa", "Marge", "Homer", "Maggie" };

    ArrayList names = new ArrayList();

    // do the smith
    for(int i = 0 ; i < Smith.length ; i ++) {
      Person one = new Person(Smith[i],"Smith");
      names.add(one);
    }

    // do the simpsons
    for(int i = 0 ; i < Simpsons.length ; i ++) {
      Person one = new Person(Simpsons[i],"Simpsons");
      names.add(one);
    }

    System.out.println("BEFORE:");
    Iterator iter1 = names.iterator();
    while (iter1.hasNext()) {
      System.out.println(iter1.next());
    }

    // now sort everything
    Collections.sort(names, new PersonComparator());

    System.out.println("AFTER:");
    Iterator iter2 = names.iterator();
    while (iter2.hasNext()) {
      System.out.println(iter2.next());
    }
    
    /*
    output :
        BEFORE:
        [ firstname=Real,lastname=Smith]
        [ firstname=Vincent,lastname=Smith]
        [ firstname=Nathalie,lastname=Smith]
        [ firstname=Christine,lastname=Smith]
        [ firstname=Bart,lastname=Simpsons]
        [ firstname=Lisa,lastname=Simpsons]
        [ firstname=Marge,lastname=Simpsons]
        [ firstname=Homer,lastname=Simpsons]
        [ firstname=Maggie,lastname=Simpsons]
        AFTER:
        [ firstname=Bart,lastname=Simpsons]
        [ firstname=Homer,lastname=Simpsons]
        [ firstname=Lisa,lastname=Simpsons]
        [ firstname=Maggie,lastname=Simpsons]
        [ firstname=Marge,lastname=Simpsons]
        [ firstname=Christine,lastname=Smith]
        [ firstname=Nathalie,lastname=Smith]
        [ firstname=Real,lastname=Smith]
        [ firstname=Vincent,lastname=Smith]    
    */
  }
}

Ruby[edit]

Output is the same as Java.

Person = Struct.new(:first_name, :last_name)
class Person
  def to_s; "[ firstname=#{first_name},lastname=#{last_name}]" end
  def <=>(other)
    [first_name, last_name] <=> [other.first_name, other.last_name]
  end
end

person = [ ["Smith",    [ "Real", "Vincent", "Nathalie", "Christine" ] ],
           ["Simpsons", [ "Bart", "Lisa", "Marge", "Homer", "Maggie" ] ] ]
names = []
person.each do |last_name, members|
  members.each do |first_name|
    names << Person.new(first_name, last_name)
  end
end

puts "BEFORE:"
names.each {|name| puts name}

names2 = names.sort_by {|name| [name.last_name, name.first_name]}

puts "AFTER:"
names2.each {|name| puts name}