分组对象列表并使用Java集合进行计数

时间:2016-08-29 08:42:52

标签: java collections count grouping

哪个Java Collection类更适合对象列表进行分组?

我有来自以下用户的消息列表:

aaa hi
bbb hello
ccc Gm
aaa  Can?
CCC   yes
ddd   No

从我想要计算的消息对象列表中显示aaa(2)+bbb(1)+ccc(2)+ddd(1)。任何代码帮助?

4 个答案:

答案 0 :(得分:4)

您可以使用Map<String, Integer>,其中键代表各个字符串,而地图值是每个字符串的计数器。

所以你可以这样做:

// where ever your input comes from: turn it into lower case,
// so that "ccc" and "CCC" go for the same counter
String item = userinput.toLowerCase(); 

// as you want a sorted list of keys, you should use a TreeMap
Map<String, Integer> stringsWithCount = new TreeMap<>();
for (String item : str) {
  if (stringsWithCount.contains(item)) {
    stringsWithCount.put(item, stringsWithCount.get(item)+1));
  } else {
    stringsWithCount.put(item, 0);
  }
}

然后你可以在完成时迭代地图:

for (Entry<String, Integer> entry : stringsWithCount.entrySet()) {

并构建结果字符串。

这就像老式的实施;如果你想让你的老师感到高兴和惊喜,你可以选择Java8 / lambda / stream解决方案。 (除非你真的花时间完全理解以下解决方案,否则我不建议这样做;因为这是我未经检验过的)

Arrays.stream(someListOrArrayContainingItems)
  .collect(Collectors
     .groupingBy(s -> s, TreeMap::new, Collectors.counting()))
  .entrySet()
  .stream()
  .flatMap(e -> Stream.of(e.getKey(), String.valueOf(e.getValue())))
  .collect(Collectors.joining())

答案 1 :(得分:1)

你需要番石榴MultiSet。该集合类型是为此类任务量身定制的

MultiSet<String> multiSet = new MultiSet<>();
for (String line : lines) { // somehow you read the lines
    multiSet.add(line.split(" ")[0].toLowerCase());
}
boolean first = true;
for (Multiset.Entry<String> entry : multiset.entrySet()) {
    if (!first) {
        System.out.println("+");
    }
    first = false;
    System.out.print(entry.getElement() + "(" + entry.getCount() + ")");            
}

答案 2 :(得分:1)

假设你使用Java 8,它可能是这样的,使用Stream API:

List<Message> messages = ...;
// Convert your list as a Stream
// Extract only the login from the Message Object
// Lowercase the login to be able to group ccc and CCC together
// Group by login using TreeMap::new as supplier to sort the result alphabetically
// Convert each entry into login(count)
// Join with a +
String result =
    messages.stream()
        .map(Message::getLogin)
        .map(String::toLowerCase)
        .collect(
            Collectors.groupingBy(
                Function.identity(), TreeMap::new, Collectors.counting()
            )
        )
        .entrySet()
        .stream()
        .map(entry -> entry.getKey() + '(' + entry.getValue() + ')')
        .collect(Collectors.joining("+"))
System.out.println(result);

<强>输出:

aaa(2)+bbb(1)+ccc(2)+ddd(1)

如果您想通过登录对邮件进行分组并将结果作为集合进行分组,则可以按下一步继续:

Map<String, List<Message>> groupedMessages = 
    messages.stream()
        .collect(
            Collectors.groupingBy(
                message -> message.getLogin().toLowerCase(), 
                TreeMap::new, 
                Collectors.toList()
            )
        );

答案 3 :(得分:1)

从其他几个答案中将各个部分放在一起,从另一个问题调整代码并修复一些琐碎的错误:

    // as you want a sorted list of keys, you should use a TreeMap
    Map<String, Integer> stringsWithCount = new TreeMap<>();
    for (Message msg : convinfo.messages) {
        // where ever your input comes from: turn it into lower case,
        // so that "ccc" and "CCC" go for the same counter
        String item = msg.userName.toLowerCase();
        if (stringsWithCount.containsKey(item)) {
            stringsWithCount.put(item, stringsWithCount.get(item) + 1);
        } else {
            stringsWithCount.put(item, 1);
        }
    }
    String result = stringsWithCount
            .entrySet()
            .stream()
            .map(entry -> entry.getKey() + '(' + entry.getValue() + ')')
            .collect(Collectors.joining("+"));
    System.out.println(result);

打印:

aaa(2)+bbb(1)+ccc(2)+ddd(1)