Bag Sum In Java

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<String, Integer> tokenList = new TreeMap<String, Integer>();
      for (String key : args) {
        tokenList.put(key, (tokenList.containsKey(key) ? tokenList.get(key) : 0) + 1);
      }
      for (Map.Entry<String, Integer> 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":""));
}
 }


EditText of this page (last edited May 23, 2009) or FindPage with title or text search