0

So i have a list

        List<String> names = new ArrayList<String>();
        names.add("Mike");
        names.add("Matthew");
        names.add("Kelly");
        names.add("Elon");
        names.add("Paul");
        names.add("Paul");
        names.add("Paul");
        names.add("Paul");
        names.add("Kelly");

I need to count all the names and then print out 3 most popular ones in descending order

Output:
Paul : 4
Kelly : 2
Mike : 1

What have i tried? I tried from most basic stuff that i have learned to Maps, treemaps and hashmaps. With last 3 i have had some success but this i could not put them into descending order. I found some tutorials from google but they were all so complicated, yes i could just copy them and get my code working but i prefer learning from it.

Got any suggestions what would be most clearest approach. Since i have never worked with maps before i do not know much about them at the moment i am writing this. In the end the output should look like this:

Output:
Paul : 44,44%
Kelly : 22,22%
Mike : 11,11%
  • 1
    Can you try reading the tutorial on the maps? Come up with what _exactly_ seems to be a problem? So far, it looks more like "could you guys please do my homework" – alf May 05 '16 at 21:44
  • Do you have to use a List, or can you use any data structure that you would like? – Fjotten May 05 '16 at 21:45
  • This should be quite a simple task to perform, all you need is a Map of String and Integer, string representing the name and Integer the number of occurrences. – Vucko May 05 '16 at 21:52

3 Answers3

0

You can do it using Java 8 :

    // creating a map with name as key and as value the number of time that name it repeat
    Map<String, Long> nameWithVlaues = names.stream()
                                            .collect(Collectors.groupingBy(s -> s, 
                                                 Collectors.counting()));

    // using a stream of de keyset of the precedent map
    nameWithVlaues.keySet()
                  .stream()
                  // sort the content of this stream using the value contained in the Map
                  .sorted((val1, val2) -> nameWithVlaues.get(val2).compareTo(nameWithVlaues.get(val1)))
                  // internal iterator over this stream
                  .forEachOrdered(name -> {
                  // getting the percent of ppl with this name
                  Long percent = (nameWithVlaues.get(name) * 100 / names.size());
                  // printing it
                  System.out.println(name + " : " + percent + "%");
                });

Without comments its seem clearer :D

    Map<String, Long> nameWithVlaues = names.stream()
                                        .collect(Collectors.groupingBy(s -> s, 
                                                 Collectors.counting()));

nameWithVlaues.keySet()
              .stream()
              .sorted((val1, val2) -> nameWithVlaues.get(val2).compareTo(nameWithVlaues.get(val1)))
              .forEachOrdered(name -> {
                Long percent = (nameWithVlaues.get(name) * 100 / names.size());
                System.out.println(name + " : " + percent + "%");
              });
Marouane S.
  • 109
  • 4
0

Another solution using java 8 could be like this :

    // creating a new comparator that compare two values by the number of their occurences in the list 
Comparator<String> comparatorOfValues = (val1, val2) -> {
  Long countVal1 = countIteration(val1, names);
  Long countVal2 = countIteration(val2, names);
  return - countVal1.compareTo(countVal2);
};

// maping function to write the result like this : NAME : 50%
Function<String, String> mapingFunction = name -> {
  return name + " : " + countIteration(name, names) * 100 / names.size() + "%";
};

// applying to names stream the comparator and the maping function and collect result as list
List<String> result2 = names.stream()
                            .distinct()
                            .sorted(comparatorOfValues)
                            .map(mapingFunction)
                            .collect(Collectors.toList());

result2.forEach(System.out::println);

And the function that count the number of iteration in a list :

  // function that count how many values in that collection matching the name 
  public static Long countIteration(String name, Collection<String> collection) {
    return collection.stream()
                     .filter(val -> name.equals(val))
                     .count();
  }
Marouane S.
  • 109
  • 4
0

There are several ways of doing this. For starters, you could code the following:

  1. Using a hash table like structure (HashMap), you count the number of times each name has occurred (frequency of each name) in the list.
  2. Now that you have the map, you can iterate over all its entries (i.e. key-value or name-frequency) pairs and choose that key (or name) that has highest frequency. Remember the simple, linear search algorithm while keeping the maximum you have seen so far? You can find the percentage in the next exercise (leave it for now). This would print, e.g. {Paul: 4}. You should not forget to remove this entry from the Map once you are done iterating.
  3. Now you know how to get to the next most frequent entry, right?
Kedar Mhaswade
  • 4,535
  • 2
  • 25
  • 34