簡単な入れ子構造を扱う #18

索引は0個以上の重複のない索引項目の並びであり、
索引項目は項目名と位置情報リストから成り、
位置情報リストは1個以上の重複のない位置情報の並びである。
項目名と位置情報はそれぞれがある順序集合の元であり、
索引における索引項目の並びは項目名によって順序付けられ、
位置情報リストは位置情報によってその並びが順序付けられる。
重複を許さないとは同順位の要素を各並びが2個以上持たないということである。

Index.java
package index;

import java.util.Set;
import java.util.TreeMap;

public class Index<N extends Comparable<N>, L extends Comparable<L>> {
    private final TreeMap<N, Item<N, L>> items = new TreeMap<N, Item<N, L>>();

    public boolean add(N name, L location) {
        Item<N, L> i = items.get(name);
        if (i == null) {
            items.put(name, new Item<N, L>(name, location));
            return true;
        } else {
            return i.add(location);
        }
    }

    public Set<N> getNames() {
        return items.keySet();
    }

    public Set<L> getLocations(N name) {
        Item<N, L> i = items.get(name);
        if (i == null) return null;
        return i.get();
    }
}
Item.java
package index;

import java.util.Set;
import java.util.TreeSet;

class Item<N, L extends Comparable<L>> {
    private final N name;
    private final TreeSet<L> locations = new TreeSet<L>();

    Item(N name, L location) {
        if (name == null) throw new IllegalArgumentException("null name");
        if (location == null) throw new IllegalArgumentException("null location");
        this.name = name;
        locations.add(location);
    }

    boolean add(L location) {
        return locations.add(location);
    }

    Set<L> get() {
        return locations;
    }
}
IndexMaker.java
import index.Index;
import java.util.Iterator;

public class IndexMaker {
    public static void main(String[] args) {
        Index<String, Integer> i = new Index<String, Integer>();
        i.add("interface", 46);
        i.add("abstract", 43);
        i.add("while", 12);
        i.add("default", 104);
        i.add("strictfp", 79);
        i.add("goto", 4);
        i.add("interface", 22);
        i.add("default", 53);
        show(i);
        for (Iterator<String> it = i.getNames().iterator(); it.hasNext(); ) {
            String n = it.next();
            if (n.equals("goto")) {
                it.remove();
            } else {
                boolean b = false;
                for (Iterator<Integer> itr = i.getLocations(n).iterator(); itr.hasNext(); ) {
                    itr.next();
                    if (b) itr.remove(); else b = true;
                }
            }
        }
        System.out.println("--- remove \"goto\" and pages except first coming");
        show(i);
    }

    private static void show(Index<String, Integer> index) {
        java.util.Set<String> ns = index.getNames();
        int m = -1;
        for (String n : ns) {
            int l = n.length();
            if (l > m) m = l;
        }
        StringBuilder s = new StringBuilder();
        for (String n : ns) {
            s.append(n);
            for (int i = n.length(); i <= m; i++) s.append(' ');
            for (int p : index.getLocations(n)) s.append(p).append(' ');
            s.deleteCharAt(s.length() - 1);
            System.out.println(s);
            s.setLength(0);
        }
    }
}