Подсчет комбинаций из последовательных символов в Java


Предположим у нас есть массив, который содержит следующие элементы:

-1, 0, 0, 1, 0, -1, 0, -1, 1

Я хотел бы считать комбинации последовательных элементов таких, что

-1,0 & 0,0 & 0,1 & 1,0 & 0,-1 & -1,0 & 0,-1 & -1&1

В этом случае:

The count of -1,0 = 2
The count of 0,1 = 1
The count of 1,0 = 1
and so on

Я реализовал следующее:

List<Double> sixProbabilites = new ArrayList<Double>();

        int count_neg10 = 0, count_neg11 = 0, count_10 = 0, count_1neg1 = 0, count_0neg1 = 0, count_01 = 0;

        for(int i=0; i<slopeChanges.size(); i++) {
            if(i+1 != slopeChanges.size()) {
                if((slopeChanges.get(i) == -1) && (slopeChanges.get(i) == 0)) {count_neg10++;}
                else if((slopeChanges.get(i) == -1) && (slopeChanges.get(i+1) == 1)) {count_neg11++;}
                else if((slopeChanges.get(i) == 1) && (slopeChanges.get(i+1) == 0)) {count_10++;}
                else if((slopeChanges.get(i) == 1) && (slopeChanges.get(i+1) == -1)) {count_1neg1++;}
                else if((slopeChanges.get(i) == 0) && (slopeChanges.get(i+1) == -1)) {count_0neg1++;}
                else if((slopeChanges.get(i) == 0) && (slopeChanges.get(i+1) == 1)) {count_01++;}
            }
        }

Нет никаких проблем с кодом, но я просто интересно, если есть способ, чтобы улучшить код, особенно если заявление. Есть ли способ, чтобы уменьшить размер кода на несколько строк?



186
5
задан 13 апреля 2018 в 03:04 Источник Поделиться
Комментарии
3 ответа

Я бы построил Map с пользовательского ввода функции и перебираем длину (минус один) массива значений.

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public class GroupFrenquency {
public static <T> Map<String, Integer> groupFrenquencies(T[] arr, Function<List<T>, String> keyFn) {
Map<String, Integer> frequency = new HashMap<>();
for (int i = 0; i < arr.length - 1; i++) {
String key = keyFn.apply(Arrays.asList(arr[i], arr[i + 1]));
frequency.put(key, frequency.containsKey(key) ? frequency.get(key) + 1 : 1);
}
return frequency;
}

public static void main(String[] args) {
Integer[] sequence = { -1, 0, 0, 1, 0, -1, 0, -1, 1 };
Function<List<Integer>, String> keyFn = (items) -> String.format("%s,%s", items.get(0), items.get(1));

System.out.println(groupFrenquencies(sequence, keyFn).entrySet().stream()
.map(e -> String.format("The count of %-4s = %d", e.getKey(), e.getValue()))
.collect(Collectors.joining(System.lineSeparator())));
}
}

Выход

The count of 0,0  = 1
The count of 0,1 = 1
The count of 1,0 = 1
The count of 0,-1 = 2
The count of -1,1 = 1
The count of -1,0 = 2


С помощью отражения, вы можете создать копию массива, а не создавать целый список объектов, при создании ключа. Единственным недостатком является то, что вам нужно пройти на тип класса из массива, потому что нельзя инициализировать общего массива без знания типа.

import java.lang.reflect.Array;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public class GroupFrenquency {
public static <T> Map<String, Integer> groupFrenquencies(Class<T> type, T[] arr, Function<T[], String> keyFn) {
Map<String, Integer> frequency = new HashMap<>();
for (int i = 0; i < arr.length - 1; i++) {
String key = keyFn.apply(copyArray(type, arr, i, 2));
frequency.put(key, frequency.containsKey(key) ? frequency.get(key) + 1 : 1);
}
return frequency;
}

@SuppressWarnings("unchecked")
private static <T> T[] copyArray(Class<T> type, T[] source, int startPos, int length) {
T[] copy = (T[]) Array.newInstance(type, length);
System.arraycopy(source, startPos, copy, 0, length);
return copy;
}

public static void main(String[] args) {
Class<Integer> type = Integer.class;
Integer[] sequence = { -1, 0, 0, 1, 0, -1, 0, -1, 1 };
Function<Integer[], String> keyFn = (items) -> String.format("%s,%s", items[0], items[1]);

System.out.println(groupFrenquencies(type, sequence, keyFn).entrySet().stream()
.map(e -> String.format("The count of %-4s = %d", e.getKey(), e.getValue()))
.collect(Collectors.joining(System.lineSeparator())));
}
}

4
ответ дан 13 апреля 2018 в 03:04 Источник Поделиться

Можно эмулировать массив с отрицательными индексами:

private void test() {
List<Integer> slopeChanges = ...
int counts[] = new int[9];
for(int i=1; i<slopeChanges.size(); i++) {
Integer current = slopeChanges.get(i-1);
Integer next = slopeChanges.get(i);
counts[index(current, next)]++;
}

System.out.println("count_neg10="+ counts[index(-1, 0)]);
}

private int index(int first, int second) {
return (first+1)*3+(second+1);
}

но это не сделает его короче.

2
ответ дан 13 апреля 2018 в 03:04 Источник Поделиться

Это всего лишь вопрос зная свои структуры данных. Вы уже представляете как List<Double> (что хорошо), теперь следующий шаг, чтобы просто представлять шаблон как List<Double> тоже тогда используйте Equals функция списки.

Естественно, вам придется перебирать список, чтобы создать 2-элементные подсписки для проверки равенства.

Таким образом, настройка комбинации (может быть сделано по-разному, главное-это структура списка:

List<List<Double>> combinations = new ArrayList<>();
for(double a = -1; a <= 1; a++) {
for(double b = -1; b <= 1; b++) {
combinations.add(Arrays.asList(a, b));
}
}

Когда у вас есть эта структура, можно просто проверить slopeChanges.sublist(i, i + 2).equals(combination) для каждого юридического я и комбинация создает. Для подсчета, используя объект изменяемым числом (которых база библиотек, отсутствие) - это esiest вещь, так вот мне использовать AtomicInteger граф:

Map<List<Double>, AtomicInteger> counts = new HashMap<>();
for(int i = 0; i < slopeChanges.size() - 1; i++) {
for(List<Double> combination : combinations) {
if(slopeChanges.subList(i, i + 2).equals(combination))
counts.computeIfAbsent(combination, k -> new AtomicInteger(0)).incrementAndGet();
}
}

0
ответ дан 16 апреля 2018 в 09:04 Источник Поделиться