6
\$\begingroup\$

The problem is stated as follows:

Given a string, return the sum of the numbers appearing in the string, ignoring all other characters. A number is a series of 1 or more digit chars in a row. (Note: Character.isDigit(char) tests if a char is one of the chars '0', '1', .. '9'. Integer.parseInt(string) converts a string to an int.)

sumNumbers("abc123xyz") → 123

sumNumbers("aa11b33") → 44

sumNumbers("7 11") → 18

Here's the program I wrote based onCharacter.isDigit(char) andInteger.parseInt(string).

public int sumNumbers(String str) {  int sum = 0;  for (int i = 0; i < str.length(); i++) {      if (Character.isDigit(str.charAt(i))) {          int count = 0;          for (int j = i; j < str.length(); j++) {              if (Character.isDigit(str.charAt(j))) count++;              else break;          }          sum += Integer.parseInt(str.substring(i, i + count));          i += count;      }  }  return sum;}

I'm not sure if I should make it more modular since it's pretty straightforward. I was wondering if I could do this withoutcount. Also, I know it's nit-picky, but I want to know if the way I format my for loops and if else statements is good style. This is just a standalone program, so I'm not really concerned about the public/private issue.

askedOct 28, 2017 at 17:42
dirtysocks45's user avatar
\$\endgroup\$

3 Answers3

5
\$\begingroup\$

I want to know if the way I format my for loops and if else statements is good style.

On the whole, yeah, looks good.

I recommend you use braces for one-liner blocks as well. In this instance, I'm not batting an eye at it—it's fine—but it's a good habit to learn.

I was wondering if I could do this withoutcount.

Yes, sincecount = j - i, you can elide it.

int sumNumbers(String str) {  int sum = 0;  for (int i = 0; i < str.length(); i++) {    if (Character.isDigit(str.charAt(i))) {      int j;      // start at i+1 because we know i has a digit      for (j = i + 1; j < str.length(); j++) {        if (!Character.isDigit(str.charAt(j))) {          break;        }      }      sum += Integer.parseInt(str.substring(i, j));      i = j;    }  }  return sum;}

Alternatively, if thebreak is a bit of an eye-sore, you could hoist the check into the for-header, but I'm not 100% it's an improvement:

int sumNumbers(String str) {  int sum = 0;  for (int i = 0; i < str.length(); i++) {    if (Character.isDigit(str.charAt(i))) {      int j;      // start at i+1 because we know i has a digit      for (j = i + 1; j < str.length() && Character.isDigit(str.charAt(j)); j++);      sum += Integer.parseInt(str.substring(i, j));      i = j;    }  }  return sum;}

Note:String.substring creates a new string since Java 7—in the reference implementation, at least, andString.toCharArray creates a new object too. If you want to avoid these allocations, you can do the char-to-digit conversion manually, but it's a bit messier, easy to muck up, and I feel that's out of scope for the exercise.

answeredOct 29, 2017 at 3:24
JvR's user avatar
\$\endgroup\$
2
  • \$\begingroup\$I like you're answer the best because it answered my individual questions even though I think Oscar Smith had a great answer as well.\$\endgroup\$CommentedOct 29, 2017 at 9:29
  • \$\begingroup\$Also, the boolean condition in the second for loop is more of an eye sore to me. I find nothing wrong withbreak.\$\endgroup\$CommentedOct 29, 2017 at 9:30
5
\$\begingroup\$

There are a couple things you can do here to make things simpler. The first is to make your inner loop a while loop instead of a for loop. With this idea, you can build up each number char by char, usingCharacter.getNumericValue() which will return1 for'1' etc. With charVal, we can incrementally build up our number by multiplying the by 10 and adding the new digit. When we reach a non-digit, we add the current num to our sum, and set sum to 0. Since the code now only operates one char at a time, we don't needi, orj either. With these changes, your updated code is

public int sumNumbers(String str) {    int sum = 0;    int num = 0;    for (char ch : exampleString.toCharArray()) {        int digit = Character.getNumericValue(ch);        if (digit >= 0 && digit <= 9) {            num = num * 10 + digit;        } else {            sum += num;            num = 0;        }    }    return sum + num;}
dirtysocks45's user avatar
dirtysocks45
1651 silver badge5 bronze badges
answeredOct 28, 2017 at 18:36
Oscar Smith's user avatar
\$\endgroup\$
9
  • \$\begingroup\$How come you don’t initialize num to 1? And I think digit would be a better name.\$\endgroup\$CommentedOct 28, 2017 at 18:49
  • 1
    \$\begingroup\$You initializenum to 0, because the first time you see a5 (eg), you wantnum*10 + 5 to equal 5, which means num needs to start at 0. It also means that when you don't hit number characters, you can addnum tosum without changing the answer.\$\endgroup\$CommentedOct 28, 2017 at 18:52
  • \$\begingroup\$You also have some typos like missing;'s and and an extra) but when I started testing your program, I get different results. Some tests are now failing.sumNumbers("abc123xyz") returns0 instead of123.\$\endgroup\$CommentedOct 28, 2017 at 19:00
  • \$\begingroup\$I edited your code to fix the above test case but cases where the integer is the last value in theString such assumNumbers("7 11") are returning the first integers like7 but forgetting about the last one like11.\$\endgroup\$CommentedOct 28, 2017 at 19:16
  • 1
    \$\begingroup\$I just fixed thesumNumbers("7 11") case\$\endgroup\$CommentedOct 28, 2017 at 19:21
1
\$\begingroup\$

Your code looks fine and is short enough to be understood.

If you don't want to work on the level of individual characters, you can use regular expressions. Here is the code:

public static int sumNumbers(String str) {    Matcher m = Pattern.compile("[0-9]+").matcher(str);    int sum = 0;    while (m.find()) {        sum += Integer.parseInt(m.group());    }    return sum;}

This is not the fastest code, but I find it easy to read once you know that[0-9] meansa digit, and the+ means1 or more times.

answeredOct 29, 2017 at 8:12
Roland Illig's user avatar
\$\endgroup\$

You mustlog in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.