5

I want to optimize this solution (idiomatically).

I have a string containing only integer values. I want to convert this string into reverse int array. The output should be an integer array

Here is my solution:

private static int[] stringToReversedIntArray(String num) {
    int[] a = new int[num.length()];
    for (int i = 0; i < num.length(); i++) {
        a[i] = Integer.parseInt(num.substring(i, i + 1));
    }
    a = reverse(a);
    return a;
}

/*
 * Reverses an int array
 */
private static int[] reverse(int[] myArray) {
    int[] reversed = new int[myArray.length];
    for (int i = 0; i < myArray.length; i++) {
        reversed[i] = myArray[myArray.length - (i + 1)];
    }
    return reversed;
}

Input: "1256346258"
Output: {8,5,2,6,4,3,6,5,2,1}

Please suggest how to do same.

Deadpool
  • 2,198
  • 9
  • 22
Abhay Agarwal
  • 538
  • 3
  • 13

8 Answers8

3
var input = "1256346258";
var result = Arrays
        .stream(new StringBuffer(input).reverse().toString().split(""))
        .map(Integer::parseInt)
        .collect(Collectors.toList());
System.out.println(result);
2

Since you are extracting one character at a time, using charAt instead of substring makes more sense.

And since you are converting a single character to an int, Character.getNumericValue() makes more sense then parseInt.

Hence I'd change

a[i] = Integer.parseInt(num.substring(i, i + 1));

to

a[i] = Character.getNumericValue(num.charAt(i));

You can also simplify the reverse part as follows if you don't mind using an Integer[] instead of int[]:

private static Integer[] stringToReversedIntArray(String num) {
    Integer[] a = new Integer[num.length()];
    for (int i = 0; i < num.length(); i++) {
        a[i] = Character.getNumericValue(num.charAt(i));
    }
    Collections.reverse(Arrays.asList(a));
    return a;
}
Eran
  • 359,724
  • 45
  • 626
  • 694
  • Small note about `getNumericValue`. It will output weird numeric values if you pass alphabet characters, while `parseInt()` is a bit safer and throws a `NumberFormatException`. Of course each is convenient in its own way. – jbx Jun 17 '19 at 07:10
  • @jbx well, the OP did say `string containing only integer values` – Eran Jun 17 '19 at 07:12
  • Yes of course, the solution is perfectly valid. Just included the note for the future reader who would like to use this option. Because it is easy to miss this subtle difference. – jbx Jun 17 '19 at 07:16
0

If you want to use streams you can do it with something like this:

Deque<String> deque = num.chars()
   .map(c -> Character.toString((char) c))
   .map(Integer::parseInt)
   .collect(Collector.of(
        ArrayDeque::new,
        (stack, i) -> stack.addFirst(i),
        (s1, s2) -> { s2.addAll(s1); return s2; })); //this combiner won't really be called unless the stream was parallel

Integer[] reversed = deque.toArray(new Integer[deque.size()]);

This loops through the list just once. The Deque can work as a stack, Last In First Out, so each addFirst() will automatically reverse the order since it adds each item to the front not the back of the list. You can convert it to an array afterwards, or use the Deque as is, which is a normal Collection and implements Iterable.

As other answers mentioned, you could also simplify it a bit like this, if you are 100% sure you have only digits, because with the simplified version you won't get a NumberFormatException.

Deque<String> deque = num.chars()
   .map(c -> Character.getNumericValue((char) c))
   .collect(Collector.of(
        ArrayDeque::new,
        (stack, i) -> stack.addFirst(i),
        (s1, s2) -> { s2.addAll(s1); return s2; }));

Integer[] reversed = deque.toArray(new Integer[deque.size()]);
jbx
  • 18,832
  • 14
  • 73
  • 129
0

No need to loop 2 times, you can use StringBuilder to reverse a String, and then loop over it to store the result in your int array:

  private static int[] stringToReversedIntArray(String num) {
    num = new StringBuilder(num).reverse().toString();
    int[] result = new int[num.length()]; 
    for (int i = 0; i < result.length; i++){
      result[i] = Character.getNumericValue(num.charAt(i)); 
    }
    return result;
  }

Other options would either be to just reverse your for loop and have it count backwards:

for(int i = array.length - 1; i >= 0; i--){
  ...
}

Or use the Stream API in recent versions of Java, as has already been mentioned above in a nice example.

TheWhiteRabbit
  • 1,193
  • 1
  • 3
  • 18
0
String str = "123456";
// Reverse String
str = new StringBuilder(str).reverse().toString();
String strArr[] = str.split("(?!^)");
// Convert to Int Array
int[] intarray = java.util.Arrays.stream(strings).mapToInt(Integer::parseInt).toArray();
Manoj Sharma
  • 819
  • 1
  • 7
  • 15
0

Erans solution is fine to me, but i dont like the for loop and i prefer if possible the stream api

String testString = "1256346258";
IntStream intStream = testString.chars();       
List<Integer> x = intStream.boxed().collect(Collectors.toList());
Collections.reverse(x);
int[] array = x.stream().mapToInt(i -> Character.getNumericValue(i)).toArray();
System.out.println("x: " + Arrays.toString(array));

just wrap it with a nice method...

ΦXocę 웃 Пepeúpa ツ
  • 43,054
  • 16
  • 58
  • 83
0

Here's a simple solution with a single for loop. You can "reverse" the digits at the same time you extract the numeric values, just by playing a bit with the indexes:

private static int[] stringToReversedIntArray(String num) {
    int len = num.length();
    int[] a = new int[len];
    for (int i = 0; i < len; i++) {
        a[i] = Character.getNumericValue(num.charAt(len - i - 1));
    }
    return a;
}
Grodriguez
  • 20,528
  • 10
  • 53
  • 97
0

One-liner:

return IntStream
    .range(0, num.length())
    .map(i -> Character.getNumericValue(num.charAt(num.length() - i - 1)))
    .toArray();
ZhekaKozlov
  • 29,055
  • 16
  • 100
  • 138