'Count of consecutive duplicate integers in a list with frequency
I want to count the number of consecutive repeating numbers from a list of bytes and show them as two integers arrays:
- The first array contains the non-repeating integer values.
- The second array contains the consequent repetition counts.
So, for an input like this:
Byte[] bytes = new Byte[] {2, 2, 2, 0, 0, 0, 0, 2, 2, 0, 0, 2};
I expect an output like this:
integers -[2, 0, 2, 0, 2]
frequency -[3, 4, 2, 2, 1]
Which is basically a compressed view of the input. The output says integer 2 repeats 3 times followed by 0 that repeats 4 times followed by 2 that repeats 2 times and so on..
I have written the below code.
List<Byte> integers = new ArrayList<>();
List<Integer> frequencies = new ArrayList<>();
for (int i=0; i < bytes.size() - 1; i++) {
Byte current = bytes.get(i);
Byte next = bytes.get(i+1);
if (current == next) {
count ++;
// if all bytes are of the same type
if (count == bytes.size() || i == bytes.size() - 2) {
integers.add(current);
frequencies.add(count);
}
continue;
integers.add(current);
frequencies.add(count);
count = 1;
}
}
System.out.println("integers " + integers + " - frequency " + frequencies);
This code works for most cases. But I am missing some edge cases. Like for the example input, the output is missing to reach to the last element 2. The output from my code for input is -
integers -[2, 0, 2, 0]
frequency -[3, 4, 2, 2]
I am adding a bunch of if statements to cover all corner cases but I want to know if there is a cleaner solution to this?
Solution 1:[1]
In Javascript we can achieve this Goal by using this Code
Make a hash(object) with keys equal to number of repetition where key is index of array where a repetition is starting and then find maximum by using For in Loop
const a = [1, 2, 2, 3, 4, 4, 5, 5, 5, 5, 3, 3, 3, 3, 3, 5, 5, 5]
let current_index = 0, count_hash = {0: 1}
for(let i = 1; i < a.length ; i++) {
const prev = a[i-1], current = a[i];
if(prev === current) {
count_hash[current_index] = count_hash[current_index] + 1;
} else {
count_hash[i] = 1;
current_index = i;
}
}
let max = count_hash['0']; index = 0;
for (let key in count_hash) {
if(count_hash[key] > max) {
max = count_hash[key];
index = key;
}
}
console.log(max, index, a[index])
Solution 2:[2]
One issue is in your use of continue.
for (int i=0; i < bytes.size() - 1; i++) {
Byte current = bytes.get(i);
Byte next = bytes.get(i+1);
if (current == next) {
count ++;
// if all bytes are of the same type
if (count == bytes.size() || i == bytes.size() - 2) {
integers.add(current);
frequencies.add(count);
}
continue;
integers.add(current);
frequencies.add(count);
count = 1;
}
}
"continue" means that it will immediately goto the top of the for-loop. So pretty much everything after the continue statement is dead code -- it'll never execute because continue means "skip to the next iteration of the for-loop." Thus, we'll never reach this code, ever:
integers.add(current);
frequencies.add(count);
count = 1;
That being said, your logic also has a flaw. It only iterates as far as the second-to-last element, because it's comparing to the next. That is, if your inputs were [1, 2, 3], it would iterate like:
- current = 1, next = 2
- current = 2, next = 3
... and that would be it. You'll need to either handle the "last number" use case outside of the loop, or update your loop to iterate to the end (and appropriately guard the get(i+1) call.) Of course, this would only be relevant if the last number and the second-to-last number were not the same; if they were, then the last number would be "counted" as a repeat of the previous.
Solution 3:[3]
You can just use this:
Byte[] bytes = new Byte[]{2, 2, 2, 0, 0, 0, 0, 2, 2, 0, 0, 2};
List<Byte> integers = new ArrayList<>();
List<Integer> frequencies = new ArrayList<>();
for (Byte b : bytes) {
if (integers.isEmpty() || !integers.get(integers.size() - 1).equals(b)) {
integers.add(b);
frequencies.add(0);
}
frequencies.set(frequencies.size() - 1, frequencies.get(frequencies.size() - 1) + 1);
}
The result will be:
integers [2, 0, 2, 0, 2]
frequency [3, 4, 2, 2, 1]
Solution 4:[4]
In the for you should do i < bytes.size()
I'll elaborate: you are running only until the before last element so if the last element is different you are missing him.
for (int i=0; i < bytes.size(); i++) {
Byte current = bytes.get(i);
// If the last byte is a single byte - then it is added with current byte and count = 1, which reseted in the previous step
// If it is consecutive value the count is correct from the increase in the previous step
if (i == bytes.size() - 1) {
integers.add(current);
frequencies.add(count);
} else {
Byte next = bytes.get(i+1);
if (current == next) {
count++;
} else {
integers.add(current);
frequencies.add(count);
count = 1;
}
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Abdullah Sandral |
| Solution 2 | Roddy of the Frozen Peas |
| Solution 3 | Samuel Philipp |
| Solution 4 |
