Альтернатива Python Counter для Java

Я использовал структуру данных Counter() в Python в качестве хранилища значений ключа, что позволяет мне сортировать объекты в соответствии с их значением, используя метод most_common. Подробнее здесь.

Есть ли подобная структура данных для языка Java? Например, я видел много связанных ответов, которые сосредоточены на сортировке HashMaps или TreeMaps по структуре данных. первоначально определенных для этой цели. В моем случае мне обычно нужно сохранять счетчики объектов, а затем выбирать наиболее распространенные или те, у которых наибольший балл (Top-N запросов). Однако мне это сложно, так как мне нужно вставить в HashMap, а затем отсортировать или использовать несколько структур данных.

2 ответа

Из здесь:

Класс Counter похож на мешки или мультимножества на других языках.

В Java нет класса Multiset или аналога. Guava имеет коллекцию MultiSet, которая делает именно то, что вы хотите.

В чистой Java вы можете использовать Map и новый метод слияния:

final Map<string, integer=""> counts = new HashMap<>();
counts.merge("Test", 1, Integer::sum);
counts.merge("Test", 1, Integer::sum);
counts.merge("Other", 1, Integer::sum);
counts.merge("Other", 1, Integer::sum);
counts.merge("Other", 1, Integer::sum);
System.out.println(counts.getOrDefault("Test", 0));
System.out.println(counts.getOrDefault("Other", 0));
System.out.println(counts.getOrDefault("Another", 0));
</string,>

Вывод:

2
3
0

Вы можете обернуть это поведение в классе в нескольких строках кода:

public class Counter<t> {
 final Map<t, integer=""> counts = new HashMap<>();
 public void add(T t) {
 counts.merge(t, 1, Integer::sum);
 }
 public int count(T t) {
 return counts.getOrDefault(t, 0);
 }
}
</t,></t>

И используйте его следующим образом:

final Counter<string> counts = new Counter<>();
counts.add("Test");
counts.add("Test");
counts.add("Other");
counts.add("Other");
counts.add("Other");
System.out.println(counts.count("Test"));
System.out.println(counts.count("Other"));
System.out.println(counts.count("Another"));
</string>

Вывод:

2
3
0


Здесь класс, который выглядит так, будто он реализует достаточно Counter, чтобы делать то, что вы хотите.

static class Counter<t> {
 final ConcurrentMap<t, integer=""> counts = new ConcurrentHashMap<>();
 public void put(T it) {
 add(it, 1);
 }
 public void add(T it, int v) {
 counts.merge(it, v, Integer::sum);
 }
 public List<t> mostCommon(int n) {
 return counts.entrySet().stream()
 // Sort by value.
 .sorted((e1, e2) -> Integer.compare(e1.getValue(), e2.getValue()))
 // Top n.
 .limit(n)
 // Keys only.
 .map(e -> e.getKey())
 // As a list.
 .collect(Collectors.toList());
 }
}
public void test() {
 Counter<string> c = new Counter<>();
 String[] numbers = {"Zero", "One", "Two", "Three", "Four", "Five", "Six"};
 for (int i = 0; i < numbers.length; i++) {
 c.add(numbers[i], i);
 }
 System.out.println(c.mostCommon(3));
}
</string></t></t,></t>

Он использует функциональность Java 8.

licensed under cc by-sa 3.0 with attribution.