1

Is there a better way to write this instead of writing multiple if statements?

I'm parsing through a document to find the instances of date and incrementing the int if an instance occurs.

public class OrganisingData {

    static int jan16=0;
    static int feb16=0;
    static int mar16=0;//... static int dec18

    public static void Months(String dates) {
        if (dates.substring(2, 4).equals("16") && 
            dates.substring(5,7).equals("01")) {
            jan16++;
        }
        if (dates.substring(2, 4).equals("16") && 
            dates.substring(5,7).equals("02")) {
            feb16++;...
        }
        if (dates.substring(2, 4).equals("18") &&
            dates.substring(5,7).equals("12")) {
            dec18++;
        }
    }
}

I am trying to build a bar chart and jan16 feb16 etc represent the month and the year and each time i find an insistence of that date (eg. 2016-01-15) i would increment jan16. so instead of writing multiple if statements for each month + year (total of 32 if statements)is there a better way to write this?

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
alo.fernando
  • 35
  • 1
  • 6
  • If the code is working, this question may be better suited for [Code Review](https://codereview.stackexchange.com/). – Turing85 Jun 25 '18 at 23:42
  • `String a = dates.substring(2, 4), b = dates.substring(5,7);` and then use `a` and `b` instead? – Elliott Frisch Jun 25 '18 at 23:44
  • 1
    You might want to use an array for your jan16, feb16, march16 … variables. Then you could use a for loop and convert your int iterator to a String and compare it with your input String. – jcroskery Jun 25 '18 at 23:47

5 Answers5

3

Basically a mix of what @John T and @Zachary said, but with proper syntax and type conversion.

// [Years] and [Months], where [0][0] is jan 2000. May need to adjust for previous years.
int[][] days = new int[30][12];

void month(String dates) {
    int year = Integer.parseInt(dates.substring(2, 4)); 
    int month = Integer.parseInt(dates.substring(5,7)) - 1;

    days[year][month]++;
}
killjoy
  • 3,665
  • 1
  • 19
  • 16
1

You could use a switch statement to reduce the clunky logic, though this wouldn't necessarily condense greatly. You will either need to use Strings with the Switch or convert the day/month values to an integer.

String day = dates.substring(2, 4);
String month = dates.substring(5, 7);

switch (month) {
    case "01" : {
        if (day.equals("16"))
            jan16++;
        break;
    }
}

If there is some pattern behind what you are wanting to do, there may be a better solution. For example, the following would count 16th of each month

int count[] = new int[12];
  ...
int day = Integer.parseInt(dates.substring(2, 4));
int month = Integer.parseInt(dates.substring(5, 7));


if (day == 16)
    count[month - 1]++;
Zachary
  • 1,693
  • 1
  • 9
  • 13
1

YearMonth

Apparently you want to track year-month values. There's a class for that, named, well, YearMonth. Find this class in the java.time package that supplants the terribly troublesome old date-time classes bundled with the earliest versions of Java.

MonthDay

Or maybe you are shooting for month-day values; your Question is convoluted so I am not sure of your goal. But if this is your goal, again, there’s a class for that: MonthDay.

Month

Or maybe you want just the month regardless of year or day-of-month, in which case you can use the Month class.

LocalDate

If your inputs strings represent a year and month and day-of-month, parse as a LocalDate. This class has no time-of-day and no time zone.

LocalDate ld = LocalDate.parse( "2016-01-15" ) ;

Extract a YearMonth, MonthDay, or Month.

YearMonth ym = YearMonth.from( ld ) ;

Create a collection. Perhaps you want to keep all a distinct set of the LocalDate objects in a particular year-month. If so, make a Map where each YearMonth object owns a Set of LocalDate objects.

Map < YearMonth, Set < LocalDate > > map = new HashMap <>();

As you process each input date, check to see if the map has a Set yet created for the particular YearMonth of the input. If not, instantiate a TreeSet. The TreeSet class is a SortedSet, meaning it maintains a sorted order as you add values.

Set < LocalDate > set = map.get( ym );
if ( null == set ) {
    set = new TreeSet <>(); // A `TreeSet` is a `SortedSet`, maintains a sorted order. You may or may not need this behavior.
    map.put( ym , set );
}

With a Set in hand, add your LocalDate.

set.add( ld );

After processing, you can get a collection of the YearMonth keys from your Map. And for each of those, you can retrieve the Set it owns, and get a count of the elements contained.

Lamba & Streams

For shorter code, you might be able to use Lambda syntax & Streams with Map::computeIfAbsent. I've seen this kind of code but have not yet tried it.

map.computeIfAbsent( key , k -> new TreeSet< LocalDate >() ).add( ld ) ;

Count only

If you want only the count, and don't care about the LocalDate values, replace Set as the “value” or you Map with a Integer object. Instead of retrieving the Set and adding to it, retrieve the Integer and increment it by adding one. Personally, in this kind of situation I find it best to collect the LocalDate values to be examined for debugging/testing and/or for further use in other business logic.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
0

Using appropriate data structures, you can greatly reduce this code. The idea is to have a data structure that for each year you're interested in, holds an array of ints: one for each month.

Then, converting the substrings from the dates String to numbers, you can use those numbers to index the data structure.

import java.util.Map;
import java.util.HashMap;

private static Map<Integer, int[]> years = new HashMap<>();
private static String[] monthNames = new String[] {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

static {
    for(int year = 16; year <= 18; year++) {
        years.put(year, new int[12]);
    }
}

public static void months(String dates) { // method names should start with lower case
    int year = Integer.parseInt(dates.substring(2, 4));
    int month = Integer.parseInt(dates.substring(5, 7)) - 1; // date String is one-based, array-index is zero-based
    years.get(year)[month]++;
}

public static void print() {
    for(int year = 16; year <= 18; year++) {
        int[] monthCounts = years.get(year);
        for(int month = 0; month < 12; month++) {
            System.out.println(monthNames[month] + " " + year + ": " + monthCounts[month]);
        }
    }
}

You can see the code in action here.

O.O.Balance
  • 2,930
  • 5
  • 23
  • 35
-2

Loop through your document with this:

// 18 years(more needed?), 12 months
String[][] yearsAndMonths = new String[18][12];  

yearsAndMonths[dates.substring(5,7)][dates.substring(2, 4)]++;

Then print the results.

I'm not a java expert. Code just provided to give you the logic.

John T
  • 814
  • 10
  • 17
  • 2
    You can't use a String to index an array. – O.O.Balance Jun 26 '18 at 00:12
  • also, I just noticed, you are declaring an array of `Strings` – you can't use the `++` operator like you would on an int. – O.O.Balance Jun 26 '18 at 00:19
  • 1
    The string array would also default everything to `null`. If you could use `++`, it would throw a `NullPointerException` – killjoy Jun 26 '18 at 00:21
  • The code was given to present the logic. I'm sure it can be adjusted to a proper way to do it in Java. – John T Jun 26 '18 at 01:48
  • That's no excuse to present code that is completely wrong. Please, either edit your post so the code contains no errors, or delete it. – O.O.Balance Jun 26 '18 at 02:24
  • @O.O.Balance I gave the logic that answered the question "Is there a better way to write this instead of writing manipulate(multiple) if statements?". I see others built on it to give a complete solution. With your reasoning there would be very few answers on SO. Most of them lack code, are incomplete or have errors, including yours. Nevertheless, they're helpful. – John T Jun 26 '18 at 02:36
  • If you've found an error in my answer, please do tell me about it so I can fix it. – O.O.Balance Jun 26 '18 at 02:59
  • Turns out I had indeed missed a `;` in my answer. I have added a link so you can see it compile and run, I believe there are no more errors. If you still think there is something wrong with my answer, please let me know. – O.O.Balance Jun 27 '18 at 02:36
  • Regarding my "reasoning": I strive to provide answers that are correct. But, what's more, I try to help both the OP and any future readers that may stumble upon the question; to that end I will often edit my answers after posting them. So when I see an answer that is not as helpful as it can be, I may comment on it. I do not mean any offense, please don't be insulted – I merely want to make sure your answer will help people, which is why we're here. As a positive side-effect to you, an improved answer is more likely to attract upvotes (and keep downvotes away). – O.O.Balance Jun 27 '18 at 02:39
  • When I see an answer that contains errors however, I think the case for editing is much stronger: We don't want to mislead our readers or teach them bad habits. I can imagine your code being copy-pasted by someone who then gets slapped in the face with multiple compile-time errors. They may even ask a question about it here – causing people to essentially waste their time dealing with it. You may want to read this blog post by our esteemed Jon Skeet: https://codeblog.jonskeet.uk/2009/02/17/answering-technical-questions-helpfully/ – O.O.Balance Jun 27 '18 at 02:44
  • @O.O.Balance I'm happy you got it working correctly. I will avoid posting both solutions and comments when I'm not able to provide a full answer. I have a family to support that is much more important. Personally I like any help in the right direction when I'm stuck, but I guess that's just me. :) – John T Jun 27 '18 at 05:45