Reputation: 20354
Not sure how to word this algorithm question, actually. I have toggle buttons in an android app, each corresponding to a numbered channel. Channels are (1,n) but the toggle button ids are some unknown, unsequential (to the buttons) integer. I need to collect the channel numbers and build a command string. My 1995-based Java skills have given me this:
String ch;
int i = 1;
for (ToggleButton toggle : toggles) {
if (toggle.isChecked()) {
ch = String.format("+%d", i+1);
channels = channels.concat(ch);
}
}
If toggle buttons 1,2,4,5,6,7,11,13,21,22,23,24,25 are checked, this code snippet successfully gives me the string "+1+2+4+5+6+7+11+13+21+22+23+24+25"
However, what I would more like to do is have the string "+1/2, +4/7, +11, +13, +21/25"
I wonder if there's an easier way to do this than multiple if statements:
String ch;
int it = 0;
int last = 1;
for (ToggleButton toggle : toggles ) {
if (toggle.isChecked()) {
if (it == last + 1) {
// somehow continue or note that we're only adding the "/"
} else {
// If we're not the next one, then build the last string
// of "n/last" and then add ", +" to start building next string
}
}
last++;
}
That seems like a bit of brute force type of algorithm, so I don't know if there's a more elegant solution that Java might have in it's bag of tricks (Or, more likely, that I should have)
Thanks.
Upvotes: 2
Views: 292
Reputation: 62789
Yours won't work, there is an end-case problem where you will have to duplicate your code to clean up after a range ends (try it on your dataset)
I know you were looking for short/terse, but my preference is to make the business logic code shorter and cleaner by doing something like this:
Counter counter=new Counter();
for(int i=1;i<=toggles.length;i++)
if(toggles.get(i).isChecked())
counter.append(i);
System.out.println(counter.getResult());
so that portion of your code is shorter, but you need a new class. This class is reusable, any time you want to re-create the same kind of range list, you've got it!. Both sections of code should be more understandable because each is only doing it's own job. It's a little longer, but honestly I'm not a fan of terse in any way, shape or form. As long as you are DRY, the more explicit the better.
PS. I'm going brace-free today.
So:
public class counter
int a=-1;
int b=-1;
String result="";
public append(int i)
if(a == -1)
a=i;
b=i;
else if(b == i-1)
b++;
else
finished();
public finished()
if(result.length != 0 && a != -1)
result+="+";
if(a != -1)
result.append(a);
if(a != b)
result.append("/"+b);
a=-1;
b=-1;
public String getResult()
finished();
return result;
Upvotes: 0
Reputation: 383956
java.util.BitSet
I'd use java.util.BitSet
both for the representation and the span search algorithm. Here's the basic idea (see on ideone.com):
import java.util.*;
//...
BitSet bs = new BitSet();
int[] onBits = new int[] { 1,2,4,5,6,7,11,13,21,22,23,24,25 };
for (int onBit : onBits) {
bs.set(onBit);
}
System.out.println(bs);
// {1, 2, 4, 5, 6, 7, 11, 13, 21, 22, 23, 24, 25}
StringBuilder sb = new StringBuilder();
for (int begin, end = -1; (begin = bs.nextSetBit(end + 1)) != -1; ) {
end = bs.nextClearBit(begin) - 1;
if (sb.length() > 0) sb.append(", ");
sb.append(
(begin == end)
? String.format("+%d", begin)
: String.format("+%d/%d", begin, end)
);
}
System.out.println(sb);
// +1/2, +4/7, +11, +13, +21/25
The nextSetBit
and nextClearBit
methods are really handy in finding the spans.
StringBuilder
instead of String
with +=/concat
The StringBuilder
joining algorithm is a standard one. Here it is when refactored out:
StringBuilder sb = new StringBuilder();
for (Element e : elements) {
if (sb.length() > 0) sb.append(SEPARATOR);
sb.append(e);
}
You should use a StringBuilder
or StringBuffer
instead of String
with +=
/concat
for building long strings.
Upvotes: 1