Below is the code to do it. I am taking help of google-guava libraries as it helps me write less code ;-). If you just want in plain java then you can modify the code also if the logic needs some tweaking then look at processLine(...) method, that is where the change will go
Ok the only missing code I see is printing empty data for the dates that are not part of the input file in a sorted order. That is simple and leave it to you. Here is the hint: Increment date by 1 & loop until end of the month
I have run your sample file and it prints the below summary
11/3/2010 cat 89 3
11/3/2010 dog 3 1
11/2/2010 dog 4 1
11/2/2010 cat 20 3
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import com.google.common.base.CharMatcher;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
import com.google.common.io.LineProcessor;
public class AnimalSummaryBuilder
{
private static final Splitter SPLITTER = Splitter.on(CharMatcher.anyOf(","));
private static final Joiner JOINER = Joiner.on("\t");
@SuppressWarnings("unchecked")
public static void main(final String[] args) throws Exception
{
@SuppressWarnings("rawtypes")
Map<Animal, Summary> result = Files.readLines(new File("c:/1.txt"), Charsets.ISO_8859_1, new LineProcessor() {
private final Map<Animal, Summary> result = Maps.newHashMap();
public Object getResult()
{
return result;
}
public boolean processLine(final String line) throws IOException
{
Iterator<String> columns = SPLITTER.split(line).iterator();
String date = columns.next();
String name = columns.next();
int value = Integer.valueOf(columns.next()).intValue();
Animal currentRow = new Animal(date, name);
if (result.containsKey(currentRow))
{
Summary summary = result.get(currentRow);
summary.increaseCount();
summary.addToTotal(value);
}
else
{
Summary initialSummary = new Summary();
initialSummary.setCount(1);
initialSummary.setTotal(value);
result.put(currentRow, initialSummary);
}
return true;
}
});
for (Map.Entry<Animal, Summary> entry : result.entrySet())
{
Animal animal = entry.getKey();
Summary summary = entry.getValue();
System.out.println(JOINER.join(animal.date, animal.name, summary.total, summary.count));
}
}
final static class Animal
{
String date;
String name;
public Animal(final String date, final String n)
{
this.date = date;
this.name = n;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((date == null) ? 0 : date.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (!(obj instanceof Animal))
{
return false;
}
Animal other = (Animal) obj;
if (date == null)
{
if (other.date != null)
{
return false;
}
}
else if (!date.equals(other.date))
{
return false;
}
if (name == null)
{
if (other.name != null)
{
return false;
}
}
else if (!name.equals(other.name))
{
return false;
}
return true;
}
}
final static class Summary
{
private int total;
private int count;
void setTotal(int value)
{
total = value;
}
void setCount(int i)
{
count = i;
}
void increaseCount()
{
count++;
}
void addToTotal(int valueToAdd)
{
total += valueToAdd;
}
}
}