Assignment 2b
Home ] Up ] Assignment 2a ] [ Assignment 2b ]

 

 

Part B: Practice with Strings

In this part of the assignment, you will write a program that accepts a set of strings of people's names, of the form:

first-name last-name

For example, here's a set to work with:

"fred bloggs", "MARY STUART",
"eRIC SuttoN", "Francis Bailey",
"Archimedes von trapp", "Abel GRISWOLD",
"Jeffrey Guay", "Alan Swasinski",
"Leroy de la Grange", "Don Ho"

(I've intentionally mixed up the case of several of these strings to ensure that you write the code to set the case properly.)

Assume that:

  • the first and last names are separated by a single space character

  • the first name does not contain any spaces

  • the last name may or may not contain one or more spaces (for example, Bailey;  von trapp, de la Grange)

  1. Make sure that each string is properly formatted:

Ensure that each string satisfies the following:

  • the first name has its first character in upper case, and its remaining characters in lower case.

  • the last name has its first character in upper case, and its remaining characters in lower case.

    • However, if the last name contains any spaces, all but its last part should be in lower case, and the first character of the last part should be upcased (for example, "Archimedes von trapp" should result in "Archimedes von Trapp" and not "Archimedes Von trapp")

Explanation: In some languages, last (family) names may consist of multiple words. For example, in French, the name "de la Grange" is a family name, and in German, the name "von Trapp" is a family name. Typically, the last word is a proper name (often a place name) and so should have its first letter upcased, while the words before it are not proper names (they are often prepositions and/or definite articles) and should not be upcased. The words "de la" in French mean "of the" or "from the", and the word "von" in German means "of" or "from".

  1. Sort the names in ascending first name order.  

    The order should be case insensitive -- that is, the sort should not differentiate between upper and lower case characters. Print out the resulting array of strings.

  1. Sort the names in ascending last name order.  

    The order should be case insensitive. Print out the resulting array of strings.

Here are some skeleton Java sources which I expect you to start from. Note that I've already done a lot of the work for you, since the main point of this exercise is for you to learn how to use the String class.   The structure of the program is already present;  all you have to do is fill in the gaps with your code.  Look for [fill in here] indicators, for where you have to supply code.

You can cut and paste from the following Java sources:

package names;

/**
*   Class to represent a person's name.
*/
public class Name implements Comparable
{
    /**
    *   Constructor
    */
    public Name(String first, String last)
    {
        m_first = first;
        m_last = last;
    }

    /**
    *   Returns whether the names are to be sorted
    *   by last name (true) or first name (false)
    */
    public boolean isSortByLast()
    {
        return m_sortByLast;
    }

    /**
    *   Sets whether the names are to be sorted
    *   by last name (true) or first name (false)
    */
    public void setSortByLast(boolean b)
    {
        m_sortByLast = b;
    }

    /**
    *   Compare this object with another object.
    *   (The other object must also be an instance of Name)
    *   NOTE: This comparison is case insensitive;  that is,
    *         letters are sorted regardless of case.
    */
    public int compareTo(Object o)
    {
        Name that = (Name) o;
        String comp1, comp2;
        int result = 0;
        if (m_sortByLast)
        {
            [fill in here]
        }
        else
        {
            [fill in here]
        }
        return result;
    }

    /**
    *   Returns a string of the form:
    *       <first-name> <last-name>
    *   where the two parts of the name are separated by a space.
    */
    public String toString()
    {
        return m_first + " " + m_last;
    }

    ///// Private data //////
    private boolean m_sortByLast = true;
    private String m_first;
    private String m_last;
}
package names;

import java.util.Arrays;

/**
*   Class to test the sorting of Names.
*/
public class NamesTest
{
    /**
    *   Main entry point.
    */
    public static void main(String[] args)
    {
        Name[] names = new Name[m_names.length];
        // populate the array with normalized names
        for (int i = 0; i < m_names.length; i++)
        {
            String name = m_names[i];
            String first = getFirstName(name);
            String last  = getLastName(name);
            names[i] = new Name(first, last);
        }
        // Sort it by last name
        Arrays.sort(names);
        System.out.println("   Names sorted by last name:");
        for (int i = 0; i < names.length; i++)
        {
            System.out.println(names[i]);
        }
        // Sort it by first name
        for (int i = 0; i < names.length; i++)
            names[i].setSortByLast(false);
        Arrays.sort(names);
        System.out.println("   Names sorted by first name:");
        for (int i = 0; i < names.length; i++)
        {
            System.out.println(names[i]);
        }
    }

    /**
    *   Extracts the first name from the specified name,
    *   normalizes it, and then returns it.
    */
    private static String getFirstName(String name)
    {
        // Get rid of any leading or trailing space
            [fill in here]
        // Find the first space
            [fill in here]
        // Extract everything before it as the first name
            [fill in here]
        // Initial cap the entire first name
            [fill in here]
        // Return the first name
    }

    /**
    *   Extracts the last name from the specified name,
    *   normalizes it, and then returns it.
    */
    private static String getLastName(String name)
    {
        // Get rid of any leading or trailing space
            [fill in here]
        // Find the first space
            [fill in here]
        // Extract everything beyond it as the last name
            [fill in here]
        // Find out whether it has an embedded space, 
        // & if it does, find the last one in the name
            [fill in here]
        if ([fill in here]) // No space found
        {
            // No space found, so just Init cap the entire last name
            [fill in here]
        }
        else
        {
            // Space found, so extract the first part
            [fill in here]
            // and lowercase it
            [fill in here]
            // Now extract the last part
            [fill in here]
            // and init cap it
            [fill in here]
            // Then reconstruct the name again, 
            // from the first and last parts
            [fill in here]
        }
        // Return the resulting normalized last name
            [fill in here]
    }

    /**
    *   Utility method to take a string (name) and set the
    *   first character to uppercase, and all the other
    *   characters to lowercase.
    */
    private static String initialCap(String name)
    {
            [fill in here]
    }

    //// Private data /////

    // The initial list of un-normalized names.
    private static String[] m_names =
    {
        "fred bloggs", "MARY STUART",
        "eRIC SuttoN", "Francis Bailey",
        "Archimedes von trapp", "Abel GRISWOLD",
        "Jeffrey Guay", "Alan Swasinski",
        "Leroy de la Grange", "Don Ho"
    };
}

Notes on the Above:

The key to understanding this is to look up the java.lang.Comparable interface in the javadocs (It's in JDK 1.2 on up).   Class Name implements the Comparable interface, which means that it's required to implement the method:

public int compareTo(Object o)

This method is used by the Arrays.sort(names) method (also in JDK 1.2 on up).

(Note:  for any of you who aren't using JDK 1.2 or higher -- please upgrade!)

Here's what the JDK 1.2 docs say about the lang.util.Arrays class's sort() method (I've underlined the critical point):


sort

public static void sort(Object[] a)

Sorts the specified array of objects into ascending order, according to the natural ordering of its elements. All elements in the array must implement the Comparable interface. Furthermore, all elements in the array must be mutually comparable (that is, e1.compareTo(e2) must not throw a ClassCastException for any elements e1 and e2 in the array).
This sort is guaranteed to be stable: equal elements will not be reordered as a result of the sort.

The sorting algorithm is a modified mergesort (in which the merge is omitted if the highest element in the low sublist is less than the lowest element in the high sublist). This algorithm offers guaranteed n*log(n) performance, and can approach linear performance on nearly sorted lists.

Parameters:

a - the array to be sorted.

Throws:

ClassCastException - if the array contains elements that are not mutually comparable (for example, strings and integers).

See Also:

Comparable



You'll note that the above refers to the Comparable interface.

Here's what the JDK 1.2 docs say about the Comparable interface's compareTo method:


compareTo

public int compareTo(Object o)

Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
The implementor must ensure sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and y. (This implies that x.compareTo(y) must throw an exception iff y.compareTo(x) throws an exception.)

The implementor must also ensure that the relation is transitive:

(x.compareTo(y)>0 && y.compareTo(z)>0) implies x.compareTo(z)>0.

Finally, the implementer must ensure that x.compareTo(y)==0 implies that sgn(x.compareTo(z)) == sgn(y.compareTo(z)), for all z.

It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y)). Generally speaking, any class that implements the Comparable interface and violates this condition should clearly indicate this fact. The recommended language is "Note: this class has a natural ordering that is inconsistent with equals."

Parameters:

o - the Object to be compared.

Returns:

a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.

Throws:

ClassCastException - if the specified object's type prevents it from being compared to this Object.


 

This page was last modified on 02 October, 2007