This is the response to the BagSumInManyProgrammingLanguages challenge, for the JavaLanguage:
In Java 5:
import java.util.*;
public class BagSum {
public static void main(String[] args) {
Map tokenList = new TreeMap();
for (String key : args) {
tokenList.put(key, (tokenList.containsKey(key) ? tokenList.get(key) : 0) + 1);
}
for (Map.Entry entry : tokenList.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
}
With JUnit 3 tests:
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import junit.framework.TestCase;
public class TestBagSum extends TestCase {
private static final String NL = System.getProperty("line.separator");
public void testEmpty() {
final String standardOutput = captureStandardOutput(new Runnable() {
@Override
public void run() {
BagSum.main(new String[0]);
}
});
assertEquals("", standardOutput);
}
public void testOneString() {
final String standardOutput = captureStandardOutput(new Runnable() {
@Override
public void run() {
BagSum.main(new String[] { "value" });
}
});
assertEquals("value: 1" + NL, standardOutput);
}
public void testTwoUnique() {
final String standardOutput = captureStandardOutput(new Runnable() {
@Override
public void run() {
BagSum.main(new String[] { "one", "two" });
}
});
assertEquals("one: 1" + NL + "two: 1" + NL, standardOutput);
}
public void testTwoOfTheSame() {
final String standardOutput = captureStandardOutput(new Runnable() {
@Override
public void run() {
BagSum.main(new String[] { "x", "x" });
}
});
assertEquals("x: 2" + NL, standardOutput);
}
public void testOriginal() {
final String standardOutput = captureStandardOutput(new Runnable() {
@Override
public void run() {
BagSum.main(new String[] { "foo", "bar", "bar", "foo", "glag", "foo" });
}
});
assertEquals("bar: 2" + NL + "foo: 3" + NL + "glag: 1" + NL, standardOutput);
}
private String captureStandardOutput(final Runnable runnable) {
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
final PrintStream printStream = new PrintStream(byteArrayOutputStream);
final PrintStream oldSystemOut = System.out;
System.setOut(printStream);
try {
runnable.run();
} finally {
System.setOut(oldSystemOut);
}
printStream.close();
return byteArrayOutputStream.toString();
}
}
Other implementations:
import java.math.BigInteger;
import java.util.*;
public class BagSum {
public static void main(String[] args) {
if (args.length == 0) args = new String[] {"foo", "bar", "bar", "foo", "glag", "foo"}; // for ease of testing
SortedMap tokenList = new TreeMap();
for (int i = 0; i < args.length; i++) {
BigInteger tokenCount = (BigInteger) tokenList.get(args[i]);
tokenCount = tokenCount == null ? BigInteger.ONE : tokenCount.add(BigInteger.ONE); // BigInteger is simpler in this case, or use Java 1.5
tokenList.put(args[i], tokenCount);
}
for (Iterator i = tokenList.keySet().iterator(); i.hasNext(); ) {
Object key = i.next();
System.out.println(key.toString() + ": " + tokenList.get(key).toString());
}
}
}
Of course, a couple of lines can be shaved as well. --ATS
(I retracted my Java solution, as ATS did a better job of it. -- JeffGrigg)
[Original more complex solution for JavaLanguage moved to ComplexBagSumInJava.]
Of course, for those who want a "one liner," there's this: ;->
import java.math.*;
import java.util.*;
public class BagSum { public static void main(String[] args) { if (args.length == 0) args = new String[] {"foo", "bar", "bar", "foo", "glag", "foo"}; SortedMap tokenList = new TreeMap(); for (int i = 0; i < args.length; i++) { BigInteger tokenCount = (BigInteger) tokenList.get(args[i]); tokenCount = tokenCount == null ? BigInteger.ONE : tokenCount.add(BigInteger.ONE); tokenList.put(args[i], tokenCount); } for (Iterator i = tokenList.keySet().iterator(); i.hasNext(); ) { Object key = i.next(); System.out.println(key.toString() + ": " + tokenList.get(key).toString()); } } }
"One-liner" is a term coined in reference to languages wherein one line is also one statement. A many-statement function delimited with something other than new line doesn't rate. --mt
Nah. Not following the DontReinventTheWheel Java principle ;-). If you're using TreeMap, why not add Apache Commons' TreeBag?
import java.util.Arrays;
import org.apache.commons.collections.Bag;
import org.apache.commons.collections.bag.TreeBag;
public class BagSum {
public static void main(String[] args) {
Bag bag = new TreeBag();
bag.addAll(Arrays.asList(args));
for (Object obj : bag.uniqueSet()) {
System.out.println(obj + ": " + bag.getCount(obj));
}
}
}
Is this valid or is too weird? (lc stands for lastChangeIndex).
public class BagSum {
public static void main(String[] args) {
java.util.Arrays.sort(args);
for (int i = 0, lc = 0; ++i <= args.length;)
if (i == args.length || !args[i].equals(args[lc]))
System.out.println(args[lc] + ": " + (-lc + (lc=i)));
}
}
or this way also (yes, sort is called a lot of times...)
public class BagSum {
public static void main(String[] args) {
for (int i = 0, lc = 0; ++i <= args.length; java.util.Arrays.sort(args), System.out.print((i == args.length || !args[i].equals(args[lc])) ? args[lc] + ": " + (-lc + (lc=i)) + "\n":""));
}
}