Home > Enterprise >  How to remove repeating code in this solution?
How to remove repeating code in this solution?

Time:10-16

I have this code which compresses the string.

with input of

aaabbccdsa

expecting output

a3b2c2dsa

My code is working properly but I think repeating if condition can be removed.

public class Solution {
    public static String getCompressedString(String str) {
        String result = "";
        char anch = str.charAt(0);
        int count = 0;

        for (int i = 0; i < str.length(); i  ) {
            char ch = str.charAt(i);

            if (ch == anch) {
                count  ;
            } else {
                if (count == 1) {           // from here
                    result  = anch;
                } else {
                    result  = anch   Integer.toString(count);                    
                }                         // to here

                anch = ch;
                count = 1;
            }

            if (i == str.length() - 1) {
                if (count == 1) {           // from here
                    result  = anch;
                } else {
                    result  = anch   Integer.toString(count);                    
                }                         // to here
            }
        }

        return result;
    }
}

In this solution code below is repeated two times

if (count == 1) {
    result  = anch;
} else {
    result  = anch   Integer.toString(count);                    
}

edit: I don't want to use the function.

CodePudding user response:

You could do away with the if statements.

   public static String getCompressedString(String str) {
        char[] a = str.toCharArray();
        StringBuilder sb = new StringBuilder();
        for(int i=0,j=0; i<a.length; i=j){
           for(j=i 1;j < a.length && a[i] == a[j]; j  );
           sb.append(a[i]).append(j-i==1?"":j-i);
        }
        return sb.toString();
   }
}

CodePudding user response:

You can use this approach as explained below:

Code:

public class Test {
    public static void main(String[] args) {
        String s = "aaabbccdsaccbbaaadsa";
        char[] strArray = s.toCharArray();
        char ch0 = strArray[0];
        int counter = 0;
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<strArray.length;i  ){
            if(ch0 == strArray[i]){//check for consecutive characters and increment the counter
                counter  ;
            } else { // when character changes while iterating
                sb.append(ch0   ""   (counter > 1 ? counter : ""));
                counter = 1; // reset the counter to 1
                ch0 = strArray[i]; // reset the ch0 with the current character
            }
            if(i == strArray.length-1){// case for last element of the string
                sb.append(ch0   ""   (counter > 1 ? counter : ""));
            }
        }
        System.out.println(sb);
    }
}

Sample Input/Output:

Input:: aaabbccdsaccbbaaadsa
Output:: a3b2c2dsac2b2a3dsa

Input:: abcdaaaaa
Output:: abcda5

CodePudding user response:

Since, the body of the else and second if is the same, so we can merge them by updating the condition. The updated body of the function will be:

String result = "";
char anch = str.charAt(0);
int count = 0;

char ch = str.charAt(0); // declare ch outside the loop, and initialize to avoid error
for (int i = 0; i < str.length(); i  ) {
    ch = str.charAt(i);

    if (ch == anch) {
        count  ;
    }
    // check if the second condition is false, or if we are at the end of the string
    if (ch != anch || i == str.length() - 1) {
        if (count == 1) { // from here
            result  = anch;
        } else {
            result  = anch   Integer.toString(count);
        } // to here
        anch = ch;
        count = 1;
    }
}

// add the condition
// if count is greater than or
// if the last character added already to the result
if (count > 1 || (len < 2 || result.charAt(len - 2) != ch)) {
    result  = ch;
}

return result;

Test Cases:

I have tested the solution on the following inputs:

aaabbccdsa -> a3b2c2dsa
aaab -> a3b
aaa -> a3
ab -> ab
aabbc -> a2b2c

Optional

If you want to make it shorter, you can update these 2 conditions.

if (count == 1) { // from here
    result  = anch;
} else {
    result  = anch   Integer.toString(count);
} // to here

as

result  = anch;
if (count != 1) { // from here
    result  = count;// no need to convert (implicit conversion)
} // to here

CodePudding user response:

Here's a single-statement solution using Stream API and regular expressions:

public static final Pattern GROUP_OF_ONE_OR_MORE = Pattern.compile("(.)\\1*");

public static String getCompressedString(String str) {
    
    return GROUP_OF_ONE_OR_MORE.matcher(str).results()
        .map(MatchResult::group)
        .map(s -> s.charAt(0)   (s.length() == 1 ? "" : String.valueOf(s.length())))
        .collect(Collectors.joining());
}

main()

public static void main(String[] args) {
    System.out.println(getCompressedString("aaabbccdsa"));
    System.out.println(getCompressedString("awswwwhhhp"));
}

Output:

a3b2c2dsa   // "aaabbccdsa"
awsw3h3p    // "awswwwhhhp"

How does it work

A regular expression "(.)\\1*" is capturing a group (.) of identical characters of length 1 or greater. Where . - denotes any symbol, and \\1 is a back reference to the group.

Method Matcher.results() "returns a stream of match results for each subsequence of the input sequence that matches the pattern".

The only thing left is to evaluate the length of each group and transform it accordingly before collecting into the resulting String.

Links:

CodePudding user response:

You can do something like this:

public static String getCompressedString(String str) {
        String result = "";
        int count = 1;
        for (int i = 0; i < str.length(); i  ) {
            if (i   1 < str.length() && str.charAt(i) == str.charAt(i   1)) {
                count  ;
            } else {
                if (count == 1) {
                    result  = str.charAt(i);
                } else {
                    result  = str.charAt(i)   ""   count;
                    count = 1;
                }
            }
        }
        return result;
    }

I got rid of the repeated code, and it do as intended.

CodePudding user response:

You can use a function which has the following 3 parameters : result, anch, count .

something of this sort:

  private static String extractedFunction(String result,int count, char anch) {
               
                return count ==1 ? (result   anch) : (result  anch Integer.toString(count) );
            }

make a function call from those two points like this :

result = extractedFunction(result,count,anch);
                  

CodePudding user response:

Try this.

static final Pattern PAT = Pattern.compile("(.)\\1*");

static String getCompressedString(String str) {
    return PAT.matcher(str)
        .replaceAll(m -> m.group(1)
              (m.group().length() == 1 ? "" : m.group().length()));
}

Test cases:

@Test
public void testGetCompressedString() {
    assertEquals("", getCompressedString(""));
    assertEquals("a", getCompressedString("a"));
    assertEquals("abc", getCompressedString("abc"));
    assertEquals("abc3", getCompressedString("abccc"));
    assertEquals("a3b2c2dsa", getCompressedString("aaabbccdsa"));
}

The regular expression "(.)\\1*" used here matches any sequence of identical characters. .replaceAll() takes a lambda expression as an argument, evaluates the lambda expression each time the pattern matches, and replaces the original string with the result. The lambda expression is passed a Matcher object containing the results of the match. Here we are receiving this object in the variable m. m.group() returns the entire matched substring, m.group(1) returns its first character.

If the input string is "aaabbccdsa", it will be processed as follows.

m.group(1)   m.group()  returned by lambda
 a            aaa        a3
 b            bb         b2
 c            cc         c2
 d            d          d
 s            s          s
 a            a          a
  • Related