Count of consecutive duplicate integers in a list with frequency

171
May 01, 2019, at 4:20 PM

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?

Answer 1

I didn't try running this code on an IDE but I think this should suffice:

int count = 1;
int index = 0;
byte current = bytes[index];
while (index < bytes.length - 1) {
    index++;
    if (bytes[index] == current) {
        count++;
    } else {
        integers.add(current);
        frequencies.add(count);
        count = 1;
        current = bytes[index];
    }
}
integers.add(current);
frequencies.add(count);
Answer 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:

  1. current = 1, next = 2
  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.

Answer 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]
Answer 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;
       }
     }
 }
Rent Charter Buses Company
READ ALSO
Hosting MP3 Files with Java

Hosting MP3 Files with Java

So I am trying to emulate something like what this site has set up:

157
Linked List sort method gives StackOverFlow Error during recursion, and comparing elements in the list

Linked List sort method gives StackOverFlow Error during recursion, and comparing elements in the list

I created Linked List from scratch, and added methods such as add, remove, set, size, etcI've also added a simple static and recursive sort method, which accepts a Linked List reference as parameter, so that it can be used in the Main class being called...

173
How to fix &ldquo;ambiguous method call&rdquo; in my code in Java in play framework

How to fix “ambiguous method call” in my code in Java in play framework

I'm following the tutorial for play framework in Java (#13) on youtube and I stuck in Index Method of BookStore ApplicationI cant go any further since I get: "Ambiguous method call

157
Spring Boot WAR deployment

Spring Boot WAR deployment

How can I control in my Spring 21

178