Как сгруппировать массив байт по количеству дубликатов?

Например есть массив байт:

116, 101, 116, 104, 101, 116

Нужно отсортировать так чтобы получился массив:

116,101,104

ну или хотя бы:

116,116,116,101,101,104

Ответы (4 шт):

Автор решения: ЮрийСПб
  1. Преобразуйте массив в List
  2. List-ом инициализируйте LinkedHashSet
  3. Создайте массив из LinkedHashSet
→ Ссылка
Автор решения: tym32167

Решение подразумевает, что порядок чисел в результате будет таким же, как в оригинальном массиве.

Если на входе у вас коллекция байт (то есть значение байта ограничено 0..255), то можно воспользоваться подсчетом, чтобы все операции заняли линейное время.

Пример

byte[] bytes = new byte[]{116, 101, 116, 104, 101, 116};

int[] counter = new int[256];

for (int i = 0; i < bytes.length; i++)
    counter[bytes[i]]++;

byte[] result = new byte[bytes.length];

int pointerNew = 0;
int pointerOld = 0;
while (pointerOld < bytes.length) {
    int count = counter[bytes[pointerOld]];
    if (count > 0) {
        for (int i = 0; i < count; i++) {
            result[pointerNew] = bytes[pointerOld];
            pointerNew++;
        }
        counter[bytes[pointerOld]] = 0;
    }
    pointerOld++;
}

System.out.println(Arrays.toString(result));

На выходе получаем

[116, 116, 116, 101, 101, 104]

Если вам на выходе нужны только уникальные значения, можно всего то поменять пару строк

byte[] bytes = new byte[]{116, 101, 116, 104, 101, 116};

int[] counter = new int[256];

int uniqueCount = 0;
for (int i = 0; i < bytes.length; i++) {
    if (counter[bytes[i]] == 0) uniqueCount++;
    counter[bytes[i]]++;
}

byte[] result = new byte[uniqueCount];

int pointerNew = 0;
int pointerOld = 0;
while (pointerOld < bytes.length) {
    int count = counter[bytes[pointerOld]];
    if (count > 0) {
        result[pointerNew] = bytes[pointerOld];
        counter[bytes[pointerOld]] = 0;
        pointerNew++;
    }
    pointerOld++;
}

System.out.println(Arrays.toString(result));

На выходе получим

[116, 101, 104]
→ Ссылка
Автор решения: Олексій Моренець
List<Integer> integerStream = list.stream()
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
                .entrySet().stream()
                .sorted((o1, o2) -> (int) (o2.getValue() - o1.getValue()))
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());

Output:

[116, 101, 104]
→ Ссылка
Автор решения: BccHnw

Можно и с BitSet поиграться (но не забывая, что byte со знаком). Если не пользоваться растущим списком, а сразу создавать массив, то два прохода. Первый подсчитывает, второй генерирует:

public class Main {
    public static void main(String[] args) {
        byte[] arr = { 116, 101, 116, 104, 101, 116, -7 };
        BitSet bitSet = new BitSet();
        for (byte rawByte : arr) {
            int value = rawByte & 0xff;
            bitSet.set(value);
        }
        byte[] result = new byte[bitSet.cardinality()];
        int index = 0;
        for (byte rawByte: arr) {
            int value = rawByte & 0xff;
            if (bitSet.get(value)) {
                result[index++] = rawByte;
                bitSet.clear(value);
            }
        }
        System.out.println(Arrays.toString(arr));
        System.out.println(Arrays.toString(result));
    }
}
→ Ссылка