2

i have got a string of names

String str = "A. Walker, L. Gordon, C. Riley, L. Gordon";

I need to count name occurancies and sort the occurancies from biggest to lowest.

I have done the countung part, but I also need to sort it.

String[] array = str.split(", ");        

List asList = Arrays.asList(array);
Set<String> mySet = new HashSet<String>(asList);
for(String s: mySet)
    System.out.println(s + " " +Collections.frequency(asList,s));

Output should look like this

L. Gordon 2, A. Walker 1, C. Riley 1
5
  • 4
    Use LinkedHashSet instead of HashSet to preserve insertion order, and sort asList before you pass it to the set. (Note, use List<String> asList rather than List asList). Commented Apr 7, 2017 at 15:14
  • And one way you can sort the list is with java.util.Collections.sort( List<T> list ). If you need a special order, you can provide a Comparator<T> via similar methods in Collections and List. Commented Apr 7, 2017 at 15:14
  • Note that if you've sorted the list, you don't need to put them into a set... Commented Apr 7, 2017 at 15:15
  • Google: java count duplicates. Commented Apr 7, 2017 at 15:17
  • If external libraries are allowed, Guava's TreeMultiset is the perfect ADT for this. Commented Apr 7, 2017 at 15:24

5 Answers 5

4

You can do something like this:

public class Test {
    static class NameFreq {
        public NameFreq(String name, int freq) {
            this.name = name;
            this.freq = freq;
        }
        String name;
        int freq;
        @Override
        public String toString() {
            return name + " " + freq;
        }
    }
    public static void main(String[] args) throws Exception {
        String str = "A. Walker, L. Gordon, C. Riley, L. Gordon";
        Map<String, NameFreq> map = new HashMap<>();
        String[] array = str.split("\\s*,\\s*");
        for(String name : array) {
            NameFreq nameFreq = map.get(name);
            if( nameFreq==null )
                map.put(name, new NameFreq(name, 1));
            else
                nameFreq.freq++;
        }

        List<NameFreq> list = new ArrayList<>(map.values());
        Collections.sort(list, new Comparator<NameFreq>() {
            @Override
            public int compare(NameFreq o1, NameFreq o2) {
                return Integer.compare(o2.freq, o1.freq);
            }
        });

        System.out.println(list);
        //output: [L. Gordon 2, A. Walker 1, C. Riley 1]
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

new Integer(o2.freq).compareTo(o1.freq) is unnecessarily boxing the int values. Use Integer.compare(o2.freq, o1.freq) instead.
Although question doesn't specify a desired ordering of names with equal count, it would be common to require a secondary sort by name. This can be done by either changing the HashMap to a TreeMap, or by enhancing the Comparator with secondary comparison logic. For performance, the second option would be better.
@Andreas is right, Integer.compare(i1, i2) method is better than new Integer(i1).compareTo(i2)
3

You can easily do it with stream, e.g.:

String str = "A. Walker, L. Gordon, C. Riley, L. Gordon";
TreeMap<String,Long> data = Arrays.stream(str.split(","))
    .map(s -> s.trim())
    .collect(Collectors.groupingBy(Function.identity(), TreeMap::new, Collectors.counting()));

LinkedHashMap<String,Long> resultMap= data.entrySet().stream()

.sorted(Map.Entry.comparingByValue().reversed()) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); System.out.println(resultMap);

If you want to strip out curly braces from the beginning and end of string, you can use substring, e.g.:

String result = resultMap.toString();
if(result.length > 2){
   result = result.substring(1, result.length() - 1);
}
System.out.println(result);

3 Comments

Nice use of groupingBy.
OP wants result sorted descending by count: "sort the occurancies from biggest to lowest"
@DarshanMehta descendingMap() is descending by key (name), not by value (count). See my answer for sorting descending by count, and for building result string correctly (your current result is A. Walker=1, C. Riley=1, L. Gordon=2, not the requested L. Gordon 2, A. Walker 1, C. Riley 1).
2

First, create a Map, keyed by name, with value being a count for that name. Then sort that descending by the value, secondary sort by key (aka name).

It seems you want result as a comma-separated string, so finally combine result that way.

Using Java 8 Streams, it can be done in a single method chain:

String str = "A. Walker, L. Gordon, C. Riley, L. Gordon";
String res = Pattern.compile(", *")
                    .splitAsStream(str)
                    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
                    .entrySet()
                    .stream()
                    .sorted(Comparator.<Entry<String, Long>, Long>comparing(Entry::getValue)
                                      .reversed()
                                      .thenComparing(Entry::getKey))
                    .map(e -> e.getKey() + " " + e.getValue())
                    .collect(Collectors.joining(", "));
System.out.println(res); // prints: L. Gordon 2, A. Walker 1, C. Riley 1

Notice the use of splitAsStream(), so the result of the split doesn't have to be stored in an intermediate array.

1 Comment

Isn't the code too complicate for this simple question?
1

Use trie to count frequency, it saves a lot of space. And use heap to sort them. While pushing in trie you can count number of distinct words. Create heap of that size, max heap if you want to sort in ascending order.

1 Comment

If you want code as well, let me know. I will write it and post.
0

Here is the simple solution by abacus-common

Stream.of(str.split(", "))
      .toMultiset()
      .toMapSortedByOccurrences(Comparators.reverseOrder());

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.