HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Compress an ASCII string

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
stringasciicompress

Problem

Given an ASCII string create a 'compressed' version of it. For example, aabccccddddddde would output a2bc4d7e whereas abc would output abc.

This is how I've implemented it. Is there a smarter way to do it without the need for two for loops?

import java.util.LinkedHashMap;
import java.util.Set;

public class CompressString {

  private static String compressString(String s) {
    LinkedHashMap charCountMap = createCharacterCountMap(s);

    StringBuilder result = new StringBuilder();
    Set keySet = charCountMap.keySet();
    for(Character c: keySet) {
      int val = charCountMap.get(c);
      if(val == 1) {
        result.append(c);
      } else {
        result.append(c.toString() + val);
      }
    }
    return result.toString();
  }

  private static LinkedHashMap createCharacterCountMap(String s) {
    char[] charArray =  s.toCharArray();
    int[] charCountArray = new int[128];
    LinkedHashMap charCountMap = new LinkedHashMap();
    for(int i=0; i<charArray.length; i++) {
      int intVal = charArray[i];
      charCountArray[intVal]++;
      charCountMap.put(charArray[i], charCountArray[intVal]);
    }
    return charCountMap;
  }

  public static void main(String[] args) {
    String s1 = "aabccccddddddde";
    String s2 = "abc";
    System.out.println(compressString(s1));
    System.out.println(compressString(s2));
  }

}

Solution

I'm commenting on the edited version only. It's fine, but

char cur = s.charAt(0);


throws for the empty string. You could special case it, but in general, it's better to do it the other way: Maintain a state containing a lastCharacter and a count. The initial state has count=0 (lastCharacter is initially arbitrary).

StringBuilder result = new StringBuilder();


You could pre-size it using s.length as it's a sure upper bound. Not very important except maybe for long strings.

result.append(cur);


Your approach needs this action at the beginning, while mine needs it at the end. You need also a complicated condition like if((i == s.length() - 1) && (count > 1)) which I don't want to understand.

for(int i=1; i<s.length(); i++) {
  char nxt = s.charAt(i);


Saving a single character compared to next is not worth it, is it?

You should also fix your spacing, especially add a space after for and if. Use your IDE.

I'd propose something like (my spacing is not conform, please ignore)

private static String compressString(String s) {
    StringBuilder result = new StringBuilder();
    int count = 0;
    char last = ' '; // doesn't matter
    for (int i=0; i0) {
        result.append(last).append(count);
    }
    return result.toString();
}


Note that whenever the string contains digits, it gets irreversibly mangled:

`11` -> `12`
`12` -> `12`

Code Snippets

char cur = s.charAt(0);
StringBuilder result = new StringBuilder();
result.append(cur);
for(int i=1; i<s.length(); i++) {
  char nxt = s.charAt(i);
private static String compressString(String s) {
    StringBuilder result = new StringBuilder();
    int count = 0;
    char last = ' '; // doesn't matter
    for (int i=0; i<s.length(); i++) {
        char c = s.charAt(i);
        if (count==0) {
            last = c;
            count = 1;            
        } else if (c==last) {
            count++;
        } else if (count==1) {
            // While this ensures the string never grows,
            // it also creates the ambiguity mentioned below.
            result.append(last);
            last = c;
        } else {
            result.append(last).append(count);
            last = c;
            count = 1;            
        }
    }
    if (count>0) {
        result.append(last).append(count);
    }
    return result.toString();
}

Context

StackExchange Code Review Q#72024, answer score: 4

Revisions (0)

No revisions yet.