Reputation: 329
I have a simple check digit calculator that I used in development stage now.
The check digit depends on the account no and constant multiplier 2187654321
. The account no is in the string format. I need to split it into array of integers.
Then every single integers need to be multiplied with their multiplier respectively.
Let say the account no is 08060002506. So the process will be 2x0 + 1x8 + 8x0...
My question is, does anyone could advice if there are more optimize ways to do the calculation? Because I will run the calculation for about thousands of account no.
Here's my code
import java.util.Arrays;
class CheckDigit {
public static void main(String[] args) {
String accountNo = "08060002506";
Integer[] multiplier = new Integer[]{2, 1, 8, 7, 6, 5, 4, 3, 2, 1};
Object[] accountNoArr = convertAccountToIntArray(accountNo);
int sum = getSum(multiplier, accountNoArr);
int remainder = getRemainder(sum);
int checkDigit = 9 - remainder;
System.out.println("Check digit is = " + checkDigit);
}
private static Object[] convertAccountToIntArray(String accountNo) {
return Arrays.stream(accountNo.split(""))
.map(Integer::parseInt).toArray();
}
private static int getSum(Integer[] multiplier, Object[] accountNoArr) {
int sum = 0;
for (int i = 0, multiplierLength = multiplier.length; i < multiplierLength; i++) {
Integer numToMultiply = (Integer) accountNoArr[i];
Integer mul = multiplier[i];
sum += mul * numToMultiply;
}
return sum;
}
private static int getRemainder(int sum) {
return sum % 9;
}
}
Upvotes: 0
Views: 368
Reputation: 168
In order to optimize the calculation I suggest to use parallel computing of streams, which is built-in function of stream api.
The problem can be treated as dot product between 2 vectors (the account and the multiplier).
This is the code for getting better run time performance:
import java.util.Arrays;
import java.util.stream.IntStream;
public class CheckDigitCalculationImprovementOrOptimization {
public static void main(String[] args) {
String accountNo = "08060002506";
int[] multiplier = {2, 1, 8, 7, 6, 5, 4, 3, 2, 1};
int[] accountNoArr = StringToIntArray(accountNo);
int result = dotProduct(multiplier, accountNoArr);
System.out.println(result);
}
private static int dotProduct(int[] v1, int[] v2) {
return IntStream.range(0, v1.length)
.parallel()
.map( id -> v2[id] * v1[id])
.reduce(0, Integer::sum);
}
static int[] StringToIntArray(String str) {
return Arrays.stream(str.split("\\B"))
.mapToInt(Integer::valueOf)
.toArray();
}
}
Another optimization step: you can prepare the conversion of accounts from string to int array in advance. I recommend to run multiple threads that will execute this task. You should create a list of int arrays, initialized with the accounts size (if this size is not constant, then use the maximum size for all of the arrays). Each thread will be responsible for filling in a fixed number of accounts with the converted string.
After joining all of the tasks from these threads, use the same technique for performing dot product between the vectors. Each thread will execute dot products between fixed amount of accounts and the given multiplier.
choosing the number of threads is tricky, and depends on the running time of individual tasks. Fine tuning approach can be useful.
Upvotes: 0
Reputation: 22343
I would use a stream approach for the getSum
because streams already provide the possibility to sum up numbers with sum()
.
public static void main(String[] args) {
String accountNo = "08060002506";
int[] multiplier = {2, 1, 8, 7, 6, 5, 4, 3, 2, 1};
int sum = getSum(multiplier, accountNo);
int remainder = sum % 9;
int checkDigit = 9 - remainder;
System.out.println("Check digit is = " + checkDigit);
}
private static int getSum(int[] multiplier, String accountNo) {
return IntStream.range(0, multiplier.length)
.map(i -> Character.digit(accountNo.charAt(i), 10) * multiplier[i])
.sum();
}
Upvotes: 3
Reputation: 201429
Prefer String.charAt(int)
and Character.digit(char, int)
to the String.split("")
and parsing of each substring (and use an int[]
instead of an Integer[]
). Something like,
public static void main(String[] args) {
String accountNo = "08060002506";
int[] multiplier = {2, 1, 8, 7, 6, 5, 4, 3, 2, 1};
int sum = getSum(multiplier, accountNo);
int remainder = getRemainder(sum);
int checkDigit = 9 - remainder;
System.out.println("Check digit is = " + checkDigit);
}
private static int getSum(int[] multiplier, String accountNo) {
int sum = 0;
for (int i = 0; i < multiplier.length; i++) {
int numToMultiply = Character.digit(accountNo.charAt(i), 10);
sum += multiplier[i] * numToMultiply;
}
return sum;
}
Upvotes: 4