Re: sorting strings with embedder digits
In article <hepsbe$gvv$1@news.albasani.net>, Lew <noone@lewscanon.com>
wrote:
Tom Anderson wrote:
return new Long(this.numericKey).compareTo(other.numericKey);
And trusting that the optimiser will flatten out the boxing and the
method call.
Or you can use Long.valueOf().
Reflecting the 1.5+ API, FindBugs elaborates: "Using [a constructor] is
guaranteed to always result in a new object, whereas valueOf() allows
caching of values to be done by the compiler, class library, or JVM.
Using cached values avoids object allocation and the code will be
faster. Values between -128 and 127 are guaranteed to have
corresponding cached instances, and using valueOf is approximately 3.5
times faster than using the constructor. For values outside the
constant range, the performance of both styles is the same. Unless the
class must be compatible with JVMs predating Java 1.5, use either
autoboxing or the valueOf() method when creating instances of Long,
Integer, Short, Character, and Byte."
To mitigate the Comparator overhead mentioned by Tom, I thought to wrap
the name in a class that implements Comparable:
<code>
import java.util.*;
import java.util.regex.Pattern;
/** @author John B. Matthews */
public class ComparableTest {
public static void main(String[] args) {
List<TrackName> list = new ArrayList<TrackName>(Arrays.asList(
new TrackName("track 10.mp3"),
new TrackName("title-1.ogg"),
new TrackName("name5.raw"),
new TrackName("file.mp3"),
new TrackName("dreck 9876543210.wav")
));
print(list, Sort.Alphabetic);
print(list, Sort.Numeric);
}
private static void print(List<TrackName> list, Sort sort) {
TrackName.sort = sort;
Collections.sort(list);
for (TrackName name : list) {
System.out.println(name);
}
}
private enum Sort { Alphabetic, Numeric; }
/** NB: this numeric ordering is inconsistent with equals. */
private static class TrackName implements Comparable<TrackName> {
private static final Pattern p = Pattern.compile("\\D+");
private static Sort sort = Sort.Numeric;
private final String name;
private Integer value = Integer.MIN_VALUE;
TrackName(String name) {
this.name = name;
Scanner s = new Scanner(trimExt(name.trim()));
try {
s.skip(p);
this.value = s.nextInt();
} catch (InputMismatchException e) {
System.err.println("Bad track: " + name);
value = Integer.MAX_VALUE;
} catch (NoSuchElementException e) {
System.err.println("No track: " + name);
}
}
private String trimExt(String s) {
int i = s.lastIndexOf('.');
return s.substring(0, i < 0 ? s.length() : i);
}
@Override
public int compareTo(TrackName o) {
if (TrackName.sort == Sort.Numeric) {
return this.value.compareTo(o.value);
} else {
return this.name.compareTo(o.name);
}
}
@Override
public String toString() {
return name;
}
}
}
</code
--
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>