简体   繁体   中英

Execute arithmetic operation on concat String with Java Streams

Hello guys and thank you all for helping.

I have a Stream<String> where a String can be something like "1+5*2-4" //= 8 (its ok if I calculate it from left to right)

This operation is no problem, but i try to do it now with Streams only.It means I need to use only stream operations like filter, reduce, collect...

I tried it for last 6 hours and have no idea. Its not allowed to build Lists and analyze the Elements or something in this direction. A stream operation or a many stream operations must give me an end result directly.

Someone any ideas?

My best try was

  Stream<String> numbers = myList.stream().filter(s -> 
  Character.isDigit(s.charAt(0)));
  List<String> operands = myList.stream().filter(s -> 
  !Character.isDigit(s.charAt(0))).collect(Collectors.toList());



   String result = numbers.reduce((a, b) -> {
   int iA = Integer.parseInt(a);
   int iB = Integer.parseInt(b);

   String operation = operands.get(0);
   operands.remove(0);
   return calc(iA,iB,operation);


  }).get();

  System.out.println(result);

Update: I probably explained it badly. The end result must deliver a stream operation. In this stream operation, we may call helper methods.

Working solution, typos corrected, thanks to @Turing85

Java-8 Stream-API is really not a magic bullet for everything and I see not any simple solution using lambda expressions.

I suggest you stick with the procedural way to go:

String string = "1+5*2-4";

String[] operator = a.split("[0-9]+");
String[] digits = a.split("[+-\\/*]");

int reduced = Integer.parseInt(digits[0]);
for (int i = 1; i < digits.length; i++) {
    if (operator[i].equals("+")) { reduced += Integer.parseInt(digits[i]); } 
    else if (operator[i].equals("/")) { reduced /= Integer.parseInt(digits[i]); } 
    else if (operator[i].equals("*")) { reduced *= Integer.parseInt(digits[i]); } 
    else if (operator[i].equals("-")) { reduced -= Integer.parseInt(digits[i]); }
}

This solution is simplified to integers only and without the input and sequence of characters checks. The number of reduced results in 8 . By the way, don't forget to escape the / character twice with \\\\ , because it has a special meaning in the Regex.


In case you really insist on the Stream-API based solution which gives the very same result, here you go:

String a = "1+5*2-4";
System.out.println(a);
String[] operator = a.split("[0-9]+");
String[] digits = a.split("[+-\\/*]");

final int[] index = {0};
int reduced = Stream.of(digits)
                    .mapToInt(Integer::parseInt)
                    .reduce(0, (int t, int u) -> 
{
    int result = Integer.parseInt(digits[0]);
    int i = index[0];
    if (operator[i].equals("+")) { result = t + u; } 
    else if (operator[i].equals("/")) { result = t / u; } 
    else if (operator[i].equals("*")) { result = t * u; } 
    else if (operator[i].equals("-")) { result = t - u; } 
    index[0]++;
    return result;
}); 

I hope now you can compare now both of the results to see which one wins in the matter of brevity and maintainability, which is in my opinion more important than show off how good you are with Stream-API and lambda expressions. However, if you challenge yourself in order to learn more about Stream-API, I suggest you to try to find other use-cases. :)


EDIT: Moreover, you should hide the operator-digit processing to a method:

public static int process(int identity, int t, int u, String[] array, int index) {
    int result = identity;
    if (array[index].equals("+")) { result = t + u; } 
    else if (array[index].equals("/")) { result =  t / u; } 
    else if (array[index].equals("*")) { result =  t * u; } 
    else if (array[index].equals("-")) { result =  t - u; }
    return result;
}

Then I might admit that Stream-API is not a bad choice.

String a = "1+5*2-4";
System.out.println(a);
String operator[] = a.split("[0-9]+");
String digits[] = a.split("[+-\\/*]");

final int[] index = {0};
int reduced = Stream.of(digits).mapToInt(Integer::parseInt).reduce(0, (int t, int u) -> {
    int result = process(Integer.parseInt(digits[0]), t, u, operator, index[0]);
    index[0]++;
    return result;
}); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM