KUROYUKI
KUROYUKI

Reputation: 123

How to count duplicate items in ArrayList in different class/java doc with multiple fields?

Does anyone know how can I get the following answer with the code I have?

aaa: 3
bbb: 2
ccc: 1

1: 2
2: 2
3: 1
4: 1

Here is what I've tried so far:

this is the main class

 package tester1;

    import java.util.ArrayList;

    public class Tester1 {


    public static void main(String[] args) {
        tester t1 = new tester(1,"aaa");
        tester t2 = new tester(2,"aaa");
        tester t3 = new tester(2,"aaa");
        tester t4 = new tester(1,"ccc");
        tester t5 = new tester(3,"bbb");
        tester t6 = new tester(4,"bbb");
        ArrayList<tester> list = new ArrayList<tester>();
        list.add(t1);
        list.add(t2);
        list.add(t3);
        list.add(t4);
        list.add(t5);
        list.add(t6);

        test t = new test(list);
        t.getter();
    }

    }

this the the class to connect to the array list

package tester1;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class test {
private ArrayList<tester> testList;

public test(ArrayList<tester> testList) {
    this.testList = testList;
}
public void getter()
{
    Set<tester>unique = new HashSet<tester>(testList);
    for(tester key:unique)
    {
        System.out.println(key.getName()+": "+Collections.frequency(testList, key.getName()));
    }
}
}

this class the where the constructor is

package tester1;


public class tester {

private int num;
private String name;

public tester(int num, String name) {
    this.num = num;
    this.name = name;
}

public int getNum() {
    return num;
}

public String getName() {
    return name;
}

}

Upvotes: 0

Views: 711

Answers (4)

Tobias Otto
Tobias Otto

Reputation: 1676

Here is another version, which simplifies some part, but shows a short lambda solution with some static-imports:

import static java.util.function.Function.identity;
import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class Tester
{

    public static void main(final String[] args)
    {
        final List<String> list = Arrays.asList("aaa", "aaa", "aaa", "ccc", "bbb", "bbb");
        final Map<String, Long> map = list.stream()
                                          .collect(groupingBy(identity(), counting()));
        System.out.println("map = " + map);
    }
}

Upvotes: 0

choasia
choasia

Reputation: 10852

list.stream()
    .collect(Collectors.groupingBy(t -> t.getName(), Collectors.counting()))
    .entrySet()
    .stream()
    .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
    .forEach(e -> System.out.println(e.getKey() + ":" + e.getValue()));

How about giving Stream a try. You don't even need the test class. You can achieve it by following 2 steps below.

  1. Group every element in the list by the number of occurrences.
  2. Sort the generated map by its number of occurrences.

Upvotes: 0

SomeJavaGuy
SomeJavaGuy

Reputation: 7347

From the javadoc of Collections#frequency:

Returns the number of elements in the specified collection equal to the specified object. More formally, returns the number of elements e in the collection such that (o == null ? e == null : o.equals(e)).

So, why does it output 0 everywhere? It´s quite simple, because the given contract can never resolve to true, as no Tester will be equal to a String.

in order to achive the correct output you have to override equals and hascode in Tester first.

// both are generated by eclipse source generation for the field name.
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Tester other = (Tester) obj;
    if (name == null) {
        if (other.name != null)
            return false;
    } else if (!name.equals(other.name))
        return false;
    return true;
}

Now you need to change your Collections#frequency call to work on the Tester and not the name field of Tester:

// replaced key.getName() with key
System.out.println(key.getName() + ": " + Collections.frequency(testList, key));

You will now have the proper output of (just not sorted by ammount of occurences):

bbb: 2
aaa: 3
ccc: 1

Upvotes: 2

nafas
nafas

Reputation: 5423

you can use a Map to store the counts:

public Map<String,Integer> getCounts(ArrayList<Tester> list){

  Map<String,Integer> counter=new HashMap<String,Integer>();

  for(Tester s : list){

    if(counter.containsKey(s.getKey())){
      counter.put(s,counter.get(s.getKey())+1);
    }else{
      counter.put(s.getKey(),1);
    }

   }

   return counter;

}

now To print you can simply iterate through your map:

for(Map.Entry<String,Integer> entry : getCounts(list).entrySet()){
    System.out.println(entry.getKey() + " : " + entry.getValue();
}

Upvotes: 0

Related Questions