3

I'm trying to figure out how to count the occurrence of an element in an ArrayList that's being broken up by dashes ---.

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");

So my ArrayList looks like this:

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

And I want my output to (alphabetically) look like this:

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

Before I had the dashes, I was getting the occurrence by using this

int occurrences = Collections.frequency(animals, "bat");

Any idea how I can achieve this?

Karol Dowbecki
  • 43,645
  • 9
  • 78
  • 111
Pam
  • 399
  • 2
  • 16
  • 3
    There is no built in function for that. You have to iterate over every single entry and start re-counting after every dash. – Murat Karagöz Aug 08 '18 at 09:46
  • 3
    Your question is not related to Android. Do not tag improperly to gain viability. – Marcin Orlowski Aug 08 '18 at 09:47
  • @MuratK. Yea, that's what I'm thinking. I'm debating on adding each element into another arraylist until I hit the dashes and then calling the frequency function that way. Either that or just do everything manually – Pam Aug 08 '18 at 09:51
  • You don't have to do that. You can use the `List::subList` method. But a manual scan would be more efficient, I believe, because you won't need to look for each and every value again and again. – RealSkeptic Aug 08 '18 at 09:53
  • [Splitting List into sublists along elements](https://stackoverflow.com/questions/29095967/splitting-list-into-sublists-along-elements) has solutions for splitting into groups which you can then calculate the frequencies from. – Mick Mnemonic Aug 08 '18 at 09:56

4 Answers4

4

It mostly depends on how do you plan to use the frequency for each value. If the objective is just to print it, then following:

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);

will output:

{bat=2, cat=1, dog=1}
{cat=1, dog=2}
{bat=2, dog=1}
Karol Dowbecki
  • 43,645
  • 9
  • 78
  • 111
  • 1
    instead of `freq.compute(animal, (k, v) -> (v == null) ? 1 : v + 1);` I would recommend `freq.merge(animal, 1, Integer::sum)` – Lino Aug 08 '18 at 10:36
0

If you're using Java8 you can construct something truly horrific, extracting the index range for each sub-list and collecting references to the elements within each range into separate lists:

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");
    ...

or alternatively iterate over the list like a normal person:

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"));
}
user234461
  • 1,133
  • 12
  • 29
0

I recommend using Multiset from guava:

    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("---");
}

Result:

bat = 2
cat = 1
dog = 1
---
cat = 1
dog = 2
---
bat = 2
dog = 1
---
Slava Vedenin
  • 58,326
  • 13
  • 40
  • 59
-4

If you want to use Collections.frequency(..), then you can create a

List<List<String>> values = new LinkedList<LinkedList<String>>();

then iterate over the animals list and add to lists to values

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"));
}

I have no IDE to test it, but that should work :)

Good luck!