Get Distinct and Count values ​​from object field in collection

I have List

objects Pin

( List<Pin>

) where the class Pin

has the following attributes:

String pinNumber, String pinType, Date insertDate

I would like to get a HashMap

s <String pinNumber, int count>

that has a separate pinNumber telling me how many different pinNumbers are in List<Pin>

and the count of each one.

This way I know to do this:

  • Iterating through List<Pin>

  • Make sure it HashMap

    already contains the key pinNumber and:
  • Increase it or add it if it doesn't exist.

I would like to do the same for each of the fields of the object Pin

.

I'm sure there must be an easier way to do this?

Maybe Guava has something simpler?

+3


source to share


4 answers


If you have the ability to use Java 8 (and since what you want to do basically sounds like a "group by" operation), this can be solved in an elegant way using the new Stream API (as hinted by user vallismortis):

import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;

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

public class Main {

    public static void main(String[] args) {
        List<Pin> pins = Arrays.asList(
                new Pin("PIN-1", "T1", new Date()),
                new Pin("PIN-1", "T2", new Date()),
                new Pin("PIN-1", "T3", new Date()),
                new Pin("PIN-2", "T2", new Date()),
                new Pin("PIN-2", "T2", new Date()),
                new Pin("PIN-3", "T2", new Date())

        );
        Map<String, Long> map = pins.stream().collect(groupingBy(Pin::getPinNumber, counting()));
        System.out.println("map = " + map);
    }
}

class Pin {
    String pinNumber;
    String pinType;
    Date insertDate;

    public Pin(String pinNumber, String pinType, Date insertDate) {
        this.pinNumber = pinNumber;
        this.pinType = pinType;
        this.insertDate = insertDate;
    }

    public String getPinNumber() {
        return pinNumber;
    }

    public String getPinType() {
        return pinType;
    }

    public Date getInsertDate() {
        return insertDate;
    }
}

      



Output:

map = {PIN-1=3, PIN-3=1, PIN-2=2}

      

+2


source


You don't need Guava for this. You can use the standard Java 8 functions. One way is with streams, but these are not suitable if you need to compute counts for multiple fields. You can use the method instead Map.merge

:

Map<String, Integer> byNumber = new HashMap<>();
Map<String, Integer> byType = new HashMap<>();
Map<Date, Integer> byInsertDate = new HashMap<>();

listOfPins.forEach(pin -> {
        byNumber.merge(pin.getPinNumber(), 1, Integer::sum);
        byType.merge(pin.getPinType(), 1, Integer::sum);
        byInsertDate.merge(pin.getInsertDate(), 1, Integer::sum);
    });

      



This has the advantage that it can only be done in one iteration over listOfPins

, whereas with streams, you need one pass for each field.

+1


source


An even simpler implementation:

public static void main(String[] args) {

    List<Pin> pinList = new ArrayList<Pin>();

    // Add employee to list
    pinList.add(new Pin("1234", "local", null));
    pinList.add(new Pin("2345", "extra", null));
    pinList.add(new Pin("3456", "extra", null));
    pinList.add(new Pin("1234", "local", null));

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

    for (Pin pin : pinList) {
        Integer cnt = mapPinNumber.get(pin.getPinNumber());
        mapPinNumber.put(pin.getPinNumber(), (cnt == null) ? 1 : ++cnt);
    }
    printMap(mapPinNumber);

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

    for (Pin pin : pinList) {
        Integer cnt = mapPinType.get(pin.getPinType());
        mapPinType.put(pin.getPinType(), (cnt == null) ? 1 : ++cnt);
    }
    printMap(mapPinType);
}

private static void printMap(Map<String, Integer> map) {
    String key;
    int value;

    for (Map.Entry<String, Integer> entry : map.entrySet()) {
        key = entry.getKey();
        value = entry.getValue();
        System.out.println(key + ": " + value);

    }
}

      

0


source


Here's one possible solution if you don't want to rely on another library and want to maintain backward compatibility with older JVMs. It's not the best or the easiest to use, but it works.

FrequencyUtil.java

import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

public class FrequencyUtil
{
    private static FrequencyUtil SINGLETON;

    private static FrequencyUtil getInstance()
    {
        if (FrequencyUtil.SINGLETON == null)
        {
            FrequencyUtil.SINGLETON = new FrequencyUtil();
        }

        return FrequencyUtil.SINGLETON;
    }

    public static <X> Map<X, Integer> frequency(final Collection<X> objects, final Comparator<X> comparator)
    {
        Map<ComparatorWrapper<X>, Integer> frequencies = new HashMap<ComparatorWrapper<X>, Integer>();

        for (X object : objects)
        {
            ComparatorWrapper<X> wrapper = FrequencyUtil.getInstance().new ComparatorWrapper<X>(object, comparator);
            Integer count = frequencies.get(wrapper);
            frequencies.put(wrapper, (count == null) ? 1 : count + 1);
        }

        // unwrap the frequencies
        Map<X, Integer> frequenciesRaw = new HashMap<X, Integer>();

        for (ComparatorWrapper<X> wrapper : frequencies.keySet())
        {
            frequenciesRaw.put(wrapper.getObject(), frequencies.get(wrapper));
        }

        return frequenciesRaw;
    }

    private class ComparatorWrapper<Z>
    {
        private Z object;
        private Comparator<Z> comparator;

        ComparatorWrapper(final Z object, final Comparator<Z> comparator)
        {
            this.object = object;
            this.comparator = comparator;
            return;
        }

        public Z getObject()
        {
            return this.object;
        }

        @Override
        public int hashCode()
        {
            return 0;
        }

        @SuppressWarnings("unchecked")
        @Override
        public boolean equals(Object obj)
        {
            if ((obj == null) || !(obj instanceof ComparatorWrapper))
            {
                return false;
            }

            return this.comparator.compare(this.object, ((ComparatorWrapper<Z>) obj).getObject()) == 0;
        }
    }
}

      

FrequencyTest.java

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

public class FrequencyTest
{
    public void test()
    {
        List<Pin> pins = new ArrayList<Pin>();

        Pin pin1 = new Pin();
        Pin pin2 = new Pin();
        Pin pin3 = new Pin();

        pin1.setPinType("typeA");
        pin2.setPinType("typeB");
        pin3.setPinType("typeA");

        pin1.setPinNumber("50");
        pin2.setPinNumber("50");
        pin3.setPinNumber("80");

        pin1.setInsertDate(Calendar.getInstance().getTime());
        pin2.setInsertDate(Calendar.getInstance().getTime());
        pin3.setInsertDate(Calendar.getInstance().getTime());

        pins.add(pin1);
        pins.add(pin2);
        pins.add(pin3);

        Comparator<Pin> pinTypeComparator = new Comparator<Pin>()
        {
            @Override
            public int compare(final Pin o1, final Pin o2)
            {
                return o1.getPinType().compareTo(o2.getPinType());
            }
        };

        Comparator<Pin> pinNumberComparator = new Comparator<Pin>()
        {
            @Override
            public int compare(final Pin o1, final Pin o2)
            {
                return o1.getPinNumber().compareTo(o2.getPinNumber());
            }
        };

        Comparator<Pin> insertDateComparator = new Comparator<Pin>()
        {
            private SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

            @Override
            public int compare(final Pin o1, final Pin o2)
            {
                return this.sdf.format(o1.getInsertDate()).compareTo(this.sdf.format(o2.getInsertDate()));
            }
        };

        Map<Pin, Integer> pinTypeFrequency = FrequencyUtil.frequency(pins, pinTypeComparator);
        Map<Pin, Integer> pinNumberFrequency = FrequencyUtil.frequency(pins, pinNumberComparator);
        Map<Pin, Integer> insertDateFrequency = FrequencyUtil.frequency(pins, insertDateComparator);

        System.out.println("pinTypeFrequency");
        for (Pin pin : pinTypeFrequency.keySet())
        {
            System.out.println(pin.getPinType() + ": " + pinTypeFrequency.get(pin));
        }

        System.out.println();
        System.out.println("pinNumberFrequency");
        for (Pin pin : pinNumberFrequency.keySet())
        {
            System.out.println(pin.getPinNumber() + ": " + pinNumberFrequency.get(pin));
        }

        System.out.println();
        System.out.println("insertDateFrequency");
        for (Pin pin : insertDateFrequency.keySet())
        {
            System.out.println(pin.getInsertDate().toString() + ": " + insertDateFrequency.get(pin));
        }
    }

    public static void main(String[] args)
    {
        try
        {
            new FrequencyTest().test();
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }

        System.exit(0);
    }
}

      

Pin.java

import java.util.Date;

public class Pin
{
    private String pinNumber;
    private String pinType;
    private Date insertDate;

    public String getPinNumber()
    {
        return pinNumber;
    }

    public void setPinNumber(String pinNumber)
    {
        this.pinNumber = pinNumber;
    }

    public String getPinType()
    {
        return pinType;
    }

    public void setPinType(String pinType)
    {
        this.pinType = pinType;
    }

    public Date getInsertDate()
    {
        return insertDate;
    }

    public void setInsertDate(Date insertDate)
    {
        this.insertDate = insertDate;
    }
}

      

Output

pinTypeFrequency typeB: 1 typeA: 2

pinNumberFrequency 80: 1 50: 2

insertDateFrequency Mon Jun 22 12:09:19 EDT 2015: 3

Just for an interesting and historical reference, Java version 1.2:

FrequencyUtil12.java

import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class FrequencyUtil
{
    private static FrequencyUtil SINGLETON;

    private static FrequencyUtil getInstance()
    {
        if (FrequencyUtil.SINGLETON == null)
        {
            FrequencyUtil.SINGLETON = new FrequencyUtil();
        }

        return FrequencyUtil.SINGLETON;
    }

    public static Map frequency(final Collection objects, final Comparator comparator)
    {
        Map frequencies = new HashMap();

        Iterator iter = objects.iterator();
        while (iter.hasNext())
        {
            Object object = iter.next();
            ComparatorWrapper wrapper = FrequencyUtil.getInstance().new ComparatorWrapper(object, comparator);
            Integer count = (Integer) frequencies.get(wrapper);
            frequencies.put(wrapper, (count == null) ? 1 : count + 1);
        }

        // unwrap the frequencies
        Map frequenciesRaw = new HashMap();

        Iterator keys = frequencies.keySet().iterator();
        while (keys.hasNext())
        {
            ComparatorWrapper wrapper = (ComparatorWrapper) keys.next();
            frequenciesRaw.put(wrapper.getObject(), frequencies.get(wrapper));
        }

        return frequenciesRaw;
    }

    private class ComparatorWrapper
    {
        private Object object;
        private Comparator comparator;

        ComparatorWrapper(final Object object, final Comparator comparator)
        {
            this.object = object;
            this.comparator = comparator;
            return;
        }

        public Object getObject()
        {
            return this.object;
        }

        public int hashCode()
        {
            return 0;
        }

        public boolean equals(Object obj)
        {
            if ((obj == null) || !(obj instanceof ComparatorWrapper))
            {
                return false;
            }

            return this.comparator.compare(this.object, ((ComparatorWrapper) obj).getObject()) == 0;
        }
    }
}

      

0


source







All Articles