将ArrayList分组并计算出现次数

3

我正在尝试弄清楚如何计算被破折号---分隔的ArrayList中元素的出现次数。

ArrayList<String> animals = new ArrayList<String>();
animals.add("dog");
animals.add("cat");
animals.add("bat");
animals.add("bat");
animals.add("---");
animals.add("cat");
animals.add("dog");
animals.add("dog");
animals.add("---");
animals.add("bat");
animals.add("bat");
animals.add("dog");

所以我的ArrayList看起来像这样:

animals = {"dog", "cat", "bat", "bat", "---", "cat", "dog", "dog", "---", "bat", "bat", "dog"}

我希望我的输出结果按字母顺序排列,如下:

bat: 2
cat: 1
dog: 1
---
cat: 1
dog: 2
---
bat: 2
dog: 1

在我使用破折号之前,我是通过以下方法获取出现次数的
int occurrences = Collections.frequency(animals, "bat");

有什么想法可以实现这个吗?

3
没有相应的内置函数,你需要迭代每个条目,在每个短划线后重新开始计数。 - Murat Karagöz
3
你的问题与Android无关。不要错误标记以获得曝光率。 - Marcin Orlowski
@MuratK。是的,这就是我在想的。我正在考虑将每个元素添加到另一个arraylist中,直到遇到破折号,然后以这种方式调用频率函数。要么就手动完成所有操作。 - Pam
你不必这样做。你可以使用 List::subList 方法。但我认为手动扫描会更有效率,因为你不需要一遍又一遍地查找每个值。 - RealSkeptic
将列表沿元素拆分为子列表有解决方案,可以将其拆分为组,然后计算频率。 - Mick Mnemonic
4个回答

4

这主要取决于您计划如何使用每个值的频率。如果目标只是打印它,则可以按照以下方式:

SortedMap<String, Integer> freq = new TreeMap<>(); // to sort keys alphabetically
for (String animal : animals) {
  if (animal.equals("---")) {
    System.out.println(freq);
    freq.clear();
  } else {
    freq.merge(animal, 1, Integer::sum);
  }
}
System.out.println(freq);

将输出:

{bat=2, cat=1, dog=1}
{cat=1, dog=2}
{bat=2, dog=1}

1
我建议使用 freq.merge(animal, 1, Integer::sum) 替代 freq.compute(animal, (k, v) -> (v == null) ? 1 : v + 1); - Lino

0
如果您正在使用Java8,您可以构建一些真正可怕的东西,提取每个子列表的索引范围,并将每个范围内元素的引用收集到单独的列表中。
int[] indexes = 
  Stream.of(IntStream.of(-1), IntStream.range(0, animals.size())
  .filter(i -> animals.get(i).equals("---")), IntStream.of(animals.size()))
  .flatMapToInt(s -> s).toArray();
List<List<String>> subSets = 
  IntStream.range(0, indexes.length - 1)
           .mapToObj(i -> animals.subList(indexes[i] + 1, indexes[i + 1]))
           .collect(Collectors.toList());

for (List l : subSets) {
    int uiBats = Collections.frequency(l, "bat");
    ...

或者像普通人一样迭代列表:

for(String value : animals){
  LinkedList<String> temp = new LinkedList<String>();
  if(value.equals("---")) {
     values.add(temp);
     temp = new LinkedList<String>();
  }else{
     temp.add(value);
  }
}
for(LinkedList<String> list : values){
  System.out.println("Frequency in " + list + " is " + Collections.frequency(list,     "bat"));
}

0

我建议使用 Guava 中的 Multiset:

    final Multiset<String> multiset = TreeMultiset.create();
    for (final String animal : animals)
    {
        if (!animal.equals("---"))
        {
            multiset.add(animal);
        } else
        {
            print(multiset);
            multiset.clear();
        }
    }
    print(multiset);
}

private static void print(final Multiset<String> multiset)
{
    multiset.entrySet().forEach(v -> System.out.println(v.getElement() + " = " + v.getCount()));

    System.out.println("---");
}

结果:

bat = 2
cat = 1
dog = 1
---
cat = 1
dog = 2
---
bat = 2
dog = 1
---

-4
如果你想使用Collections.frequency(..),那么你可以创建一个。
List<List<String>> values = new LinkedList<LinkedList<String>>();

然后迭代动物列表并将列表添加到值中。
for(String value : animals){
  LinkedList<String> temp = new LinkedList<String>();
  if(value.equals("---")) {
     values.add(temp);
     temp = new LinkedList<String>();
  }else{
     temp.add(value);
  }
}
for(LinkedList<String> list : values){
  System.out.println("Frequency in " + list + " is " + Collections.frequency(list, "bat"));
}

我没有IDE来测试它,但应该可以工作 :)

祝你好运!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接