Reputation: 21
Here is the scenario, I have monthly data that I have to insert into a data structure and then retrieve it. So say Data a goes into Jan month, Data b goes into June month, and Data c goes into Jan month. Once the inserts are done, then I add all the data for a given month and retrieve it. So for Jan it will be a+b, for Feb it could be d+e+f and so forth. How can I accomplish this in Java? Kindly help. Thanks Matt
Upvotes: 1
Views: 761
Reputation: 339362
Month
enum, EnumMap
, and functional streamsThe modern approach uses java.time classes, a Map
, and perhaps even the functional side of Java with Java Streams.
The Month
enum defines a dozen objects, one for each month of the year. Use EnumMap
as your Map
, because it is highly optimized for enums as your keys.
Map < Month, List < Integer > > map = new EnumMap( Month.class );
Put an empty ArrayList<Integer>
as the value for each key. The ArrayList
can only hold objects (Integer
), not primitives (int
). Fortunately, auto-boxing converts back-and-forth for us automatically.
// Pre-populate.
for ( Month m : EnumSet.allOf( Month.class ) ) {
map.put( m , new ArrayList <>() );
}
// Add some data.
List < Integer > list;
list = map.get( Month.FEBRUARY );
list.addAll( List.of( 1 , 2 , 3 ) );
list = map.get( Month.MAY );
list.addAll( List.of( 44 , 22 ) );
Loop through each key, getting the list for each. If the list is empty, skip it (or you could report zero). If not empty, loop to add the values of the elements in the list. Again, auto-boxing to the rescue for object↔primitive conversion.
For reporting, we ask the Month
enum object to generate a localized name for that month in English, French, whatever.
// Report
for ( Month m : map.keySet() ) {
list = map.get( m );
if ( ! list.isEmpty() ) {
int sum = 0;
for ( Integer integer : list ) {
sum = ( sum + integer );
}
System.out.println( m.getDisplayName( TextStyle.FULL , Locale.US ) + " = " + sum );
}
}
February = 6
May = 66
Instead of looping, we can use the functional approach in Java, using Java Streams to calculate an aggregate. Discussed on other Questions, here and here and here.
// Report
for ( Month m : map.keySet() ) {
list = map.get( m );
if ( ! list.isEmpty() ) {
int sum = list.stream().mapToInt( Integer :: intValue ).sum();
System.out.println( m.getDisplayName( TextStyle.FULL , Locale.US ) + " = " + sum );
}
}
Upvotes: 0
Reputation: 1340
If you are asking for a Map
you may try something like this:
// Month enum.
enum Month {JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC}
// Map for storing months against values.
Map<Month, Double> monthMap = new HashMap<Month, Double>();
// Initialize month map with 0.0 value. You may implement it differently.
void initMonthMap() {
for (Month m : Month.values()) {
monthMap.put(m, 0.0);
}
}
// Function to add values to a month.
void addValue(Month m, Double v) {
monthMap.put(m, monthMap.get(m) + v);
}
// Eg. Adding values to a month.
addValue(Month.JAN, 12.0);
Later you can fetch the summed up values for any/every month.
Upvotes: 0
Reputation: 77474
How about using an Array/ArrayList with 12 entries?
ArrayList<ArrayList<Double>> data = new ArrayList<>(12);
You need to initialize it:
for (int i = 0; i < 12) {
data.add(new ArrayList<Double>());
}
You then can add data by:
data.get(month - 1).add(123.);
Note that indexes start with 0.
Warning: Collections of primitive objects don't scale very well. They need much more memory than necessary. If you have lots of data, using GNU Trove may pay off quickly.
However, if you just want to sum them, how about doing this:
double[] sums = new double[12];
sums[month - 1] += value;
Just compute the 12 sums right away.
Upvotes: 3