31. srpna 2007

Třídění kolekcí podle českých pravidel

Narazil jsem včera na zajímavé možnosti třídění kolekcí v Javě. Můj problém byl následující - z LDAP serveru načítám uživatele a potřebuji je pak setřídit dle jejich příjmení. Vzhledem k tomu, že ne všechny LDAP servery mají zabudovanou funkcionalitu třídění, tak jsem toto musel vyřešit přímo v Javě.

První řešení, které asi každého hned napadne je následující:

  public static final Comparator SURNAME_COMPARATOR_ASC = new Comparator() {
public int compare(Object o1, Object o2) {
return ((User) o1).getSurname().compareTo(((User) o2).getSurname());
}
};
...
// sort users by surname
Collections.sort(users, SURNAME_COMPARATOR_ASC);
Nadefinuji si standardní komparátor a pak použiji metodu z Collections pro třídění. A zde jsem narazil na problém s řazením v češtině - příjmení začínající diakritikou se seřadily až na úplný konec seznamu, což je špatně. Je to tím, že používáme standardní komparátor Stringu, který řadí řetězce lexikograficky.

Java umí zde parádně pomoci třídou Collator. Tato třída bere v potaz pravidla pro jednotlivé národní znaky, pomocí RuleBasedCollator je možné si dokonce nadefinovat úplně vlastní pravidla pro třídění. A aby toho nebylo málo, tak je tu ještě třída CollationKey pro efektivnější třídění řetězců.

Nová implementace komparátoru bude tedy vypadat takto:
  private static Collator czechCollator = Collator.getInstance(new Locale("cs"));

public static final Comparator SURNAME_COMPARATOR_ASC = new Comparator() {
public int compare(Object o1, Object o2) {
return czechCollator.compare(((User) o1).getSurname(), ((User) o2).getSurname());
}
};

2 komentáře:

rus řekl(a)...

pekne elegantni reseni, zrovna jsem se s necim podobnym potykal, vubec jsem nevedel, ze tohle Java umi, jo ten jazyk me asi nikdy neprestane prekvapovat ;))

Vít Jurásek řekl(a)...

Problém je, že tohle defaultní řazení pro český jazyk není úplně podle ISO normy, takže vzniká problém třeba s řazením mezery ("ABC" je před "AB C" což je špatně)
Nějaké jednoduché řešení jsem zatím nenašel.