How does this code add commas before every three digits? - java

Help me to understand how this code works. It essentially adds commas into a string of numbers. So if the user types a 1 to 3 digit number it is unchanged. For a four digit number ,it adds a comma so
1111 becomes 1,111
11111 becomes 11,111
111111111 becomes 11,111,111
and so on. Here's the code:
private String addCommasToNumericString (String digits)
{
String result = "";
int len = digits.length();
int nDigits = 0;
for (int i = len - 1; i >= 0; i--)
{
result = digits.charAt(i) + result;
nDigits++;
if (((nDigits % 3) == 0) && (i > 0))
{
result = "," + result;
}
}
return (result);
}
I´ll explain what I do understand of it
The for loop basically counts the length of the number the user has written to avoid putting a comma before the first number (e.g. ,1111). And while i is less than the length of the string it subtracts 1.
result returns the char at position i, since it counts downwards it returns the chars "opposite" from right towards left.
nDigits adds 1 from to the initial value of 0 on each iteration through the loop.
I guess now is where I am having trouble seeing exactly what is going on: if ("nDigits % 3) == 0.
So for the two first iteration through loop it will not execute the if loop because:
1 % 3 = 1
2 % 3 = 2
3 % 3 = 0
nDigits starts out as 1 because of the nDigits++ code inside the for loop, so how does it put the comma after three digits and not two? And how does it know when there is only 4 or 5 digits to place the comma corretly at position 1 and two (1,111 - 11,111)?

I think the easiest way to explain this is to slow it down to each pass.
The loop starts at the end of the string so if you have the string 12345, then after the first time through the loop result will be "5" and nDigits will be 1.
The next time through, '4' will be added to the front of the result giving you "45" and nDigits will be 2.
The third time through, it adds '3' to the front of result making that "345" and then the if-then triggers and adds a comma to the front. Result is now ",345".
More passes will give you "12,345".
I think what is confusing you is that loop starts at the '5' and not at the '1'. Everything is added to the front of result and not to the end as you would normally expect.
Hope this helps!

The key thing in this method is to count the digits from right to left. If you don't do it that way it won't work.
You can also do the same with String Manipulation instead of char manipulation. Maybe it makes it easier to understand so I'll provide an example.
My solution involves the use of the subString Method and operates in a similar manner to yours. Starting FROM RIGHT TO LEFT, it divides the original String in two substrings and adds a comma in between them every time there is a 3 digits group.
private String addCommas (String digits) {
String result = digits;
if (digits.length() <= 3) return digits; // If the original value has 3 digits or less it returns that value
for (int i = 0; i < (digits.length() – 1) / 3; i++) {
int commaPos = digits.length() – 3 – (3 * i); // comma position in each cicle
result = result.substring(0, commaPos) + "," + result.substring(commaPos);
}
return result;
}

The variable result is used for incremental build of the final output, in each iteration one or two chars are concatenated from left (i.e. the string is build from right to left).
One char is concatenated everytime by running
result = digits.charAt(i) + result;
it is the actual digit
the second char is concatenated in each third iteration by running
result = "," + result;
it is the order separator
The implementation is not optimal at all, because in Java the string are immutable and result = "," + result; ends up in creating a new object. The StringBuffer or StringBuilder are far more effective for this purpose.

Essentially what this does is start at the last digit of the number and iterate through from right to left, prepending them to the result String and putting a comma in every 3 characters.
In this particular code, len holds the total length of the number and nDigits is a count of how many of those digits have been evaluated already. Starting at position len-1 (so the index of the last digit of the number), the for-loop iterates through position 0 (the first digit of the number). It takes the digit at position i, puts it at the front of the result String, and then evaluates if there should be a comma in front of it. nDigits % 3 will return 0 every 3rd digit, so the if statement evaluates if there should be a comma by checking that if there have been 3 digits written and the one you just wrote was not 0.

for (int i = len - 1; i >= 0; i--)
i starts with len - 1, to start from the last digit. i > 0 in if (((nDigits % 3) == 0) && (i > 0)) is the one that avoid a comma before the first number (e.g. ,1111).

I modified answer of #Antonio Ricardo Diegues Silva for my purposes.
/**
* Get number in {#link String} with divider after 'n' number of digits
* #param number number for processing
* #param n amount after which will be inserted divider
* #return {#link String} number with dividers
*/
public static <T extends Number> String insertDividerBetweenEveryNDigits(T number, int n, String divider) {
StringBuilder builder = new StringBuilder().append(number);
int digitsNumber = builder.length();
if (digitsNumber > n) { // If the original value has n digits or less it just returns that value
for (int i = 1; i <= (digitsNumber - 1) / n; i++) {
int dividerPos = digitsNumber - (n * i); // divider position in each cycle
builder.insert(dividerPos, divider);
}
}
return builder.toString();
}

Related

How to sum consecutive equal digits in a number in Java

The following question was asked in my last interview (yesterday), and I'm trying to solve it since then (couldn't solve it in the interview).
Sorry for any grammar mistakes or any logical mistakes, I don't have the question, it was written by memory:
You are given a number in a string format, for example: "14438832066".
You got to sum up the consecutive equal digits in that number. If no
consecutive equal digit was found, just add the digit to the result.
for example: solution(19938832066) => 11831632012
Explanation: first digit is 1.
The second and third digits are both 9 which means they will turn into 18 in the result string.
So on
with the rest of the digits (as you can see, the last 2 digits are both 6 which means they will turn into 12 in the result string).
You are required to do that for the result string as well, if needed, until no equal consecutive digits are found in the number.
Example:: number: 14438832066 solution( "19938832066") ->"11831632012" -> "2831632012"
Explanation: first result is 11831632012, but then you can see that there are still equal consecutive digits : the first and the
second digits are both 1. So process that number as well.
You are given a string and must return a string.
My solution:
I couldn't write the solution, I don't know why. It's a pretty simple question, I thought going recursive at first but didn't want to complex things.
I wrote 2 helper methods:
one that returns a boolean whether the number consists of equal consecutive digits.
one that actually makes the business logic:
turn the string into a char array
create a counter that will count instances of the same digit - (int counter = 1).
loop on the array from the first to the one before the last element :
inside the loop:
//equal digit was found - increment counter and continue to next digit
if char[i] == char[i+1] then counter++
//calculation in case we are done counting the same digit
else if counter > 0 then result.append(counter*digit[i])
// if no consecutive equal digit was found
else result.append(digit[i])
end loop: return result
Problems I had:
I created the counter inside the loop, so each iteration it got rested. took me few minutes to realize.
I had troubles realizing that 'int(digit[i])' doesn't give me the numeric value of the char, it gives the ASCII value. I had to use "Character.getNumericValue" (don't remember the exact name of the method).
Because of these problems, it took me 45 minutes to write the solution which in the end didn't even work.
I'll be glad to get a working solution, and even better - to get any feedback and tips on my solution and what, in your opinion, were my mistakes.
Thank you.
Your pseudo-code seems alright, as far as it goes. What's missing is that you don't repeatedly check the result string to see if another pass is required. I also show how you don't need to remember the API to convert a character to a digit; if you know the digits are decimal, you can interpret them yourself. As an interviewer, I would accept that there is an API that you can't precisely remember or your home-brew solution as equally valid.
String transform(String number) {
while (true) {
String result = collapse(number);
if (result.equals(number)) return result;
number = result;
}
}
private static String collapse(String number) {
StringBuilder result = new StringBuilder();
for (idx = 0; idx < number.length(); ) {
int mark = idx;
int digit = digitAt(number, idx++);
while (idx < number.length() && digitAt(number, idx) == digit) ++idx;
result.append((idx - mark) * digit);
}
return result.toString();
}
private static int digitAt(String num, int index) {
char ch = number.charAt(index);
if (ch < '0' || ch > '9') throw new IllegalArgumentException();
return ch - '0';
}
The preceding is a naïve approach that transforms the string until there are no changes. I suspect there might be a more "elegant" approach that works from left to right through the input in a single pass, but it would take some thought, and I probably couldn't come up with that in an interview.
Here's an algorithm that uses recursion and a for-loop to add consecutive equal digits. I think the code is pretty self-explanatory but please ask if you have any queries.
public static String addConsecutiveDigits(String number) {
char[] arr = number.toCharArray();
StringBuilder result = new StringBuilder();
boolean foundConsecutive = false; // boolean flag for checking if the number contained consecutive equal digits
for (int i = 0; i < arr.length; i++) {
int digit = arr[i] - '0'; //Subtracting ascii values to get integer values
int newNumber = digit;
if (i != arr.length - 1) {
int nextDigit = arr[i + 1] - '0';
if (digit == nextDigit) { // check if the digits are consecutive digits
newNumber = digit + nextDigit;
i++; // increment i as we have already added the i+1 digit
foundConsecutive = true;
}
}
result.append(newNumber);
}
if (!foundConsecutive) // if no consecutive equal digits were found then return the result;
return result.toString();
else // recurse to check for more consecutive equal digits
return addConsecutiveDigits(result.toString());
}
I'm not a Java guy, so this code might not be ideal but I would do something like this:
public String solve(String input)
{
String result = "";
int i = 0;
while (i < input.length())
{
var first = input.charAt(i);
if (i == input.length() - 1){
result += first;
break;
}
var second = input.charAt(i + 1);
if (first == second){
result += (Character.getNumericValue(first) + Character.getNumericValue(second));
i += 2;
} else {
result += first;
i += 1;
}
}
return result;
}
For the second part, I would just run the function in a loop until the result matches the input.

How does this code calculate sum of entered number

I've been learning Java for one week now and I came across this solution for my homework, but I just can't understand how it calculates the sum of numbers.
I've tried to understand it for 1 hour now and I feel so dumb right now.
I pretty much understand that for add to x + 1 every time when the length of the entered number is lower than x which is 0. But I just can't get what the code inside for does.
sum += Integer.parseInt(String.valueOf(a.charAt(x)));
Here is the full code
public class Loader {
public static void main(String[] args) {
System.out.println(sum(8313));
}
public static Integer sum(Integer number){
String a = Integer.toString(number);
Integer sum = 0;
for(int x = 0; x < a.length(); x++) {
sum += Integer.parseInt(String.valueOf(a.charAt(x)));
}
return sum;
}
}
Actually, what you understood was wrong. (Or at least how you put it into words).
The for loop is used to loop through a range of numbers. In this case, it loops through 0 to a.length(), which is the number of digits in your number (The number variable). So in each iteration (or the step of the loop), the value of the x increases. It's not 0 all the time.
In each iteration, the for loop checks whether the x is still lesser than the number of digits in your number. If it reaches the limit, the loop exits.
Before entering the loop, you convert the number to a String. So, inside the loop, you first get the character at the index of the value of x. Basically, you take the character by character in your number. Then you convert it back to a digit using:
Integer.parseInt(String.valueOf(a.charAt(x)))
Then, it is added to the sum. This is pretty much the same as this:
for(int x = 0; x < a.length(); x++) {
char c = a.charAt(x);
String s = String.valueOf(c);
int digit = Integer.parseInt(s);
sum = sum + digit;
}
Your code just does all four steps in one line! When you come up with such cases, try to break down the code like this. That'll help you to understand it better.
Let's break down the line sum += Integer.parseInt(String.valueOf(a.charAt(x)));
First of all sum += 1 is the same as sum = sum + 1, so sum += Integer.parseInt(String.valueOf(a.charAt(x))); is equal to sum = sum + Integer.parseInt(String.valueOf(a.charAt(x)));
Integer.parseInt("1") transforms the String "1" into a number, so "1" => 1. Adding a variable of the type String to a number like sum += "1" would give an error
String.valueOf() on the other hand can transform a number or other datatype into a String, so 1 => "1". In this case it is used to transform a Character to the String datatype
a.charAt(x) takes the Character from the String a at the point x So if you have a = "Brentspine" then a.charAt(1) would return "r", since indexing starts at 0
So the line takes the character at position x from the String and makes it a string. Character is its own class so it has to be transformed into a String. Then this String is transformed into a number and added to the sum variable
The fori loop repeats itself the length of the String a times. For every time it run, the x variable gets increased by 1. This way it adds the number at the position x of the String a to the sum variable, which gets returned.
It basically says for the input "8315":
Repeat 4 times, increase x=0 by 1 every time.
Take the Character of the String at position a, make it an int and add it to sum

Code after if block inside a for loop doesn't work

I'm new to java. This is a question about if block in a for loop. This code is from a algorithm practice.
The code is to take an int array but treat it as an integer and add one to this integer, and convert the new integer back to array format. if I didn't describe it clearly, please refer to the original here.
public static int[] plusOne(int[] digits) {
int size = digits.length;
for(int i=size-1; i>=0; i--) {
if(digits[i] < 9) {
System.out.println("tag1 digits.i = " + digits[i]);
digits[i]++;
System.out.println("tag2 digits.i = " + digits[i]);
return digits; // <-- return
}
System.out.println("tag3 digits.i= " + digits[i]);
digits[i] = 0; //?
System.out.println("tag4 digits.i= " + digits[i]);
}
int[] intOut = new int [size+1];
intOut[0] = 1;
return intOut;
}
In the codes above, I added some println() to show how digit[i] changes.
When the input is {1,2,3}, why the line of digits[i] = 0 doesnt work? Reading the code I thought all int in int[] digits will be set to 0.
If it return in the if block, does it mean stop the current iteration and ignore the rest code in the for loop after the if block?
update I failed to describe it clearly.My question was not on what and how to accomplish with the code, but about given the input i mentioned, why the code after if statement doesn't work. And now i learnt that the return statement at the last line of the if block means to do it(stop current iteration). Sorry for this silly question..!
Your code add one to the number passed as digit array.
So when you add 1 to 123, you get 124. The code starts with the last digit, looks whether it is less than 9, then add 1 only to the last digit.
this happens in the if-block. The return ends the function
The code which sets a digit to 0 will only reached when there is some overflow. This overflow can only happen when you pass a number where the last digit is 9.
To reach this case you must pass something like 129 (or {1,2,9}). Then the last digit become 0 and the second last digit is checked. In this case added by one, return 130
To reach the code behind the loop, you have to pass a list where all digits are set to 9. For example 99 (or {9,9}).
In this case, the last digit will set to 0, the first digit will set to 0, then a new list will be generates with one more digit. Initially all digits are set to 0. Then the first digit will be set to 1. This results in 100.
return leaves the function/method
break leaves the surrounding loop (for,while)
So the answer to your question in bold is YES
For the below loop:
for(int i=size-1; i>=0; i--) {
if(digits[i] < 9) {
System.out.println("tag1 digits.i = " + digits[i]);
digits[i]++;
System.out.println("tag2 digits.i = " + digits[i]);
return digits;
}
System.out.println("tag3 digits.i= " + digits[i]);
digits[i] = 0; //?
System.out.println("tag4 digits.i= " + digits[i]);
}
The moment digit[i] < 9 it will go inside the if condition. But after that it will return the digit[] and will come out of the method.
Hence you will never see digit[i] < 9 i.e. 1 to 8 being set to 0.

Converting a decimal number to binary in java not showing leading zeroes

This is my function in Java:
public static String convertFromDecimal(int number, int base)
{
String result = "";
/*
* This while loop will keep running until 'number' is not 0
*/
while(number != 0)
{
result = (number%base) + result; // Appending the remainder
number = number / base; // Dividing the number by the base so we can get the next remainder
}
// If the number is already 0, then the while loop will ignore it, so we will return "0"
if(result == "")
{
return "0";
}
return result;
}
It works fine for numbers that convert to numbers not beginning with 0, if the number is supposed to have a zero at the start, it will not record it, could anyone tell me why?
For example, if I print out
convertFromDecimal(13,2) it returns
1101
Which is correct, but if I print out
convertFromDecimal(461,2), I get
111001101
Where the actual answer is
0000000111001101
So it's the same as my answer without the leading zeroes, if anyone knows why I would appreciate the help, thank you.
EDIT My question is different because I don't want 16 digits, I want the binary number of the given decimal, a calculator like this can explain what I want.
I assume you are looking to format all your answers as shorts (16 bits).
In this case, simply check the length of your current string, and add on zeroes as needed.
int zeroesRemaining = 16 - result.length();
for (int i = 0; i < zeroesRemaining; i++) {
result = "0" + result;
}
Alternatively, if you want to do it faster, use a StringBuilder.
int zeroesRemaining = 16 - result.length();
StringBuilder tempBuilder = new StringBuilder(result);
for (int i = 0; i < zeroesRemaining; i++) {
tempBuilder.insert(0, 0); //inserts the integer 0 at position 0 of the stringbuilder
}
return tempBuilder.toString(); //converts to string format
There is also probably a formatter that could do this, but I don't know of such.
If you want to change the number of zeroes to be the closest integer primitive, just set zeroesRemaining to be the (least power of 2 that is greater than the number of bits) minus (the number of bits).
Since you want fixed lengths for your result, in groups of 8 bits, the easiest way is to append 0 to the front of your result until its length is a multiple of 8.
That is as simple as
wile (result.length() % 8 > 0)
{
result = "0" + result;
}
return result;

Create random String of numbers with specific requirements

I want to create a random String of numbers.
From 0-9.
10 digits long.
First digit cannot be a 0.
One of the digits has to be in the String 2 times and one has to not be there at all.
Or one digit has to be there 3 times, and 2 other digits can not be there at all.
To make this a little bit clearer here are some examples:
1223456789 - 10 digits, no starting zero, one digit (2) is there 2 times and one digit (0) is not there at all
1000345678 - 10 digits, no starting zero, one digit (0) is there 3 times and two digits (2,9) are not there at all
The starting zero is pretty easy caught with startsWith - method, but I have not found a way to check for the rest and I am not particularly good at regex while I am also not entirely sure you can even do this using regex.
For generating the random String itself, I have worked with the Random class as well as RandomStringUtils, both of which don't have restrictions on creating numbers.
Has anyone of you an idea how to achieve this?
Imagine you have 10 sacks, each one of them has its corresponding number embroided on it, from 0 to 9, like this:
.---.._
{------';
}====={
.´ '.
/ .´| \ inside there are
| | | <--- stones with '1' engraved
\: _|_ /
-__ =.´
You also have a coin to flip heads or tails on your hand.
.------..-
´ . /___ `.`.
; / / ´} ; ; ______________________________
: "|'__' // : : / |
' .|/__\. } \ ' ' /_ HEAD! You shall pick 3 |
' /"../ ' ' | stones from the 1st sack! |
; / \/ ͷ ; ; \____________________________/
`_/ ´ ´
" -------´-´
First, we will decide if we will have 3 repeating numbers or 2 repeating numbers. Flip the coin to decide! Tail is 3, Head is 2. We will call this result ͷ.
Remove the sack embroided with 0 (Zero) for a moment.
Now pick ͷ (2 or 3) stones from a random sack of the 9 sacks you have in front of you. Remember, you cannot start with 0, that is why we removed it for a moment! Remove the sack you just picked from the line of sacks, forever. You cannot pick from this one anymore. Put back the 0 (Zero) sack on the line.
Place one of the stones you just picked in front of yourself. Hold ͷ-1 in your hand.
Now repeat this until you have 9 stones in your hand:
Select a random sack, pick ONE stone from it and hold it in your hand. Remove the sack from the
line.
By the end of this process, you will have 9 stones in your hand, one in front of yourself. Shuffle up the ones in your hand. Place them in a straight line in front of yourself, next to the stone that was already in front of you.
You will end with 10 numbers, ͷ repetitions of the same number, won't start with zero, and the remaining sack(s) in front of you are just a side-effect of removing the sacks along the way.
What about trying to make what you want first using the rules then construct the rest.
Here is a possible idea
Using the first rule
One of the digits has to be in the String 2 times and one has to not be there at all.
Create a LinkedList then add the numbers 1 to 9 to it.
Generate a random number between 0-8 (range of the indexes of the list), use the index to retrieve a value out of the list (as in delete it) then add that to the String so the first number isn't 0.
Add 0 back to the list so it can be used somewhere else.
There are now 9 numbers left in the LinkedList with the first number being non zero and already in the String variable as per step 2. From here, generate another random number in the range of the LinkedList indexes. Whatever this number is, remove it from the LinkedList add it twice to the ArrayList.
There are now 8 numbers left in the LinkedList, 1 non zero number in the String. and 3 numbers in the ArrayList for a total of 4 numbers in your sequence that are confirmed to be correct. You have to get another 6 numbers to complete it. So far it would look something like this.
String sequence => "4"
ArrayList beingBuilt => [2, 6, 6]
LinkedList available => [1, 3, 4, 5, 7, 8, 9, 0]
Seems you only can have 10 numbers, loop 6 more times through the LinkedList using a random number to pluck at a random index, delete it from LinkedList add it to ArrayList.
After this the ArrayList should have 9 numbers, you could shuffle it to make it more random then convert it to a String and append to on the end of the sequence. Your rule should be satisfied now.
To make it more random you could manipulate how you pluck out numbers from the LinkedList and also the last rule you had you could change it for that too fairly simply. I used a LinkedList due to faster deletes, I did think about using a set but perhaps more work to handle the random number index being mapped to a number that actually exists in the set.
Just an idea though
The idea is: first generate a random string with 0-9 each once and not starts with 0, then: 1. replace one of the digital will another or 2.replace two digitals with another.
import java.util.Random;
public class Main {
public static void main(String[] args) {
System.out.println(generateRandomString());
System.out.println(generateRandomString());
}
public static String generateRandomString() {
String alphabet = "0123456789";
String result = "";
Random random = new Random();
// build a random string construct will 0-9 and each digital appear once
for (int i = 0; i < 10; i++) {
int index = random.nextInt(alphabet.length());
if (i == 0) { // first cannot be 0
index = random.nextInt(alphabet.length() - 1) + 1;
}
String c = alphabet.substring(index, index + 1);
result += c;
alphabet = alphabet.replace(c, "");
}
return random.nextInt(2) == 0 ? shuffle1(random, result) : shuffle2(random, result);
}
// One of the digits has to be in the String 2 times and one has to not be there at all.
private static String shuffle1(Random random, String result) {
int from = random.nextInt(10);
int to = random.nextInt(9) + 1;
while (from == to) {
to = random.nextInt(9) + 1;
}
result = result.replace(result.substring(to, to + 1), result.substring(from, from + 1));
return result;
}
// One digit has to be there 3 times, and 2 other digits can not be there at all
private static String shuffle2(Random random, String result) {
int from = random.nextInt(10);
int to1 = random.nextInt(9) + 1;
int to2 = random.nextInt(9) + 1;
while (from == to1) {
to1 = random.nextInt(9) + 1;
}
while (from == to2 || to2 == to1) {
to2 = random.nextInt(9) + 1;
}
result = result.replace(result.substring(to1, to1 + 1), result.substring(from, from + 1));
result = result.replace(result.substring(to2, to2 + 1), result.substring(from, from + 1));
return result;
}
}
If you're not too concerned about performance then the simplest thing would be to just generate random lists of numbers and check them against your conditions until you get one that works. Best to do the filtering as numbers and then convert to a string at the end rather than using regular expressions.
public String getRandomInts() {
Random random = new Random();
int[] ints;
do {
ints = random.ints(10, 0, 10).toArray();
} while (!meetsCriteria(ints));
return Arrays.stream(ints).mapToObj(String::valueOf).collect(Collectors.joining(""));
}
private boolean meetsCriteria(int[] ints) {
if (ints[0] == 0) {
return false;
}
if (frequency(ints, 0) == 1
&& frequency(ints, 1) == 8
&& frequency(ints, 2) == 1) {
return true;
}
if (frequency(ints, 0) == 2
&& frequency(ints, 1) == 7
&& frequency(ints, 3) == 1) {
return true;
}
return false;
}
private int frequency(int[] ints, int count) {
return (int) IntStream.range(0, 10)
.filter(n1 -> Arrays.stream(ints).filter(n2 -> n1 == n2).count() == count)
.count();
}

Categories