web-dev-qa-db-fra.com

Java-get, plus le Élément Une liste Dans commun

Est-ce que Java ou Guava ont quelque chose qui retournera l'élément le plus courant dans une liste?

List<BigDecimal> listOfNumbers=  new ArrayList<BigDecimal>(); 

[1,3,4,3,4,3,2,3,3,3,3,3]

retour 3

14
Doc Holiday

C'est assez facile à mettre en œuvre vous-même:

public static <T> T mostCommon(List<T> list) {
    Map<T, Integer> map = new HashMap<>();

    for (T t : list) {
        Integer val = map.get(t);
        map.put(t, val == null ? 1 : val + 1);
    }

    Entry<T, Integer> max = null;

    for (Entry<T, Integer> e : map.entrySet()) {
        if (max == null || e.getValue() > max.getValue())
            max = e;
    }

    return max.getKey();
}

List<Integer> list = Arrays.asList(1,3,4,3,4,3,2,3,3,3,3,3);
System.out.println(mostCommon(list));
 3 

Si vous souhaitez gérer les cas dans lesquels il y a plus d'un élément le plus fréquent, vous pouvez parcourir la liste une fois pour déterminer le nombre d'occurrences du ou des éléments les plus fréquents, puis parcourir à nouveau la liste, placer ces éléments dans un ensemble et les renvoyer. cette.

20
arshajii

Probablement la solution la plus simple avec Guava ressemble à

Multiset<BigDecimal> multiset = HashMultiset.create(listOfNumbers);
BigDecimal maxElement = null;
int maxCount = 0;
for (Multiset.Entry<BigDecimal> entry : multiset.entrySet()) {
  if (entry.getCount() > maxCount) {
    maxElement = entry.getElement();
    maxCount = entry.getCount();
  }
}

C'est une solution complète et plus courte que les autres alternatives que je vois discutées.

15
Louis Wasserman

En statistique, cela s'appelle le "mode" . Une solution Vanilla Java 8 ressemble à ceci:

Stream.of(1, 3, 4, 3, 4, 3, 2, 3, 3, 3, 3, 3)
      .collect(Collectors.groupingBy(Functions.identity(), Collectors.counting()))
      .entrySet()
      .stream()
      .max(Comparator.comparing(Entry::getValue))
      .ifPresent(System.out::println);

Quels rendements:

3=8

jOOλ est une bibliothèque qui prend en charge mode() sur les flux. Le programme suivant:

System.out.println(
    Seq.of(1, 3, 4, 3, 4, 3, 2, 3, 3, 3, 3, 3)
       .mode()
);

Rendements:

Optional[3]

Par souci de simplicité, j'ai omis d'utiliser BigDecimal. La solution serait la même, cependant.

(disclaimer: je travaille pour la société derrière jOOλ)

13
Lukas Eder

Voici une solution pure Java 8 (note: n'utilisez pas celle-ci, voir ci-dessous):

List<Integer> theList = Arrays.asList(1, 3, 4, 3, 4, 3, 2, 3, 3, 3, 3, 3);
Integer maxOccurredElement = theList.stream()
        .reduce(BinaryOperator.maxBy((o1, o2) -> Collections.frequency(theList, o1) -
                        Collections.frequency(theList, o2))).orElse(null);
System.out.println(maxOccurredElement);

Une autre solution consiste à collecter les éléments d’une carte par leur fréquence, puis à rechercher l’entrée avec la valeur max et à la restituer (la même solution sur la réponse de arshajii , écrite en Java 8):

Integer maxVal = theList.stream()
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
                .entrySet().stream().max((o1, o2) -> o1.getValue().compareTo(o2.getValue()))
                .map(Map.Entry::getKey).orElse(null);

Mise à jour: Si les éléments les plus fréquents sont plusieurs, et que vous voulez tous les avoir dans une collection, je propose deux méthodes:

Méthode A: Après avoir collecté la collection d'origine sur une carte avec des clés en tant qu'éléments et des valeurs en nombre d'occurrences, obtenir l'entrée avec la valeur maximale et filtrer les entrées de la carte avec une valeur égale à cette valeur maximale (si ) nous avons trouvé. Quelque chose comme ça:

Map<Integer, Long> elementCountMap = theList.stream()
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
List<Integer> result = elementCountMap.values().stream()
        .max(Long::compareTo).map(maxValue -> elementCountMap.entrySet().stream()
            .filter(entry -> maxValue.equals(entry.getValue())).map(Map.Entry::getKey).collect(Collectors.toList()))
        .orElse(Collections.emptyList());

Méthode B: Après avoir collecté la collection d'origine sur une carte avec des clés en tant qu'éléments et des valeurs en nombre d'occurrences, la transformation de cette carte en une nouvelle carte avec des clés en nombre d'occurrences, des valeurs en tant que liste d'éléments ce nombre d'occurrences. Et ensuite, trouver l'élément max de cette carte avec un comparateur personnalisé qui compare les clés et obtenir la valeur de cette entrée. Comme ça:

List<Integer> result = theList.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
    .entrySet().stream()
    .collect(Collectors.groupingBy(Map.Entry::getValue, Collectors.mapping(Map.Entry::getKey, Collectors.toList())))
    .entrySet().stream().max((o1, o2) -> o1.getKey().compareTo(o2.getKey())).map(Map.Entry::getValue)
    .orElse(Collections.emptyList());
9
Utku Özdemir

Guava fournit une méthode qui vous aidera, même si elle est moins efficace que la solution de Louis.

BigDecimal mostCommon = 
    Multisets.copyHighestCountFirst(ImmutableMultiset.copyOf(listOfNumbers))
        .iterator().next();
7
Jared Levy

La méthode classique consiste à trier la liste, puis à la parcourir une par une:

public static BigInteger findMostCommon(List<BigInteger> list) {
    Collections.sort(list);
    BigInteger mostCommon = null;
    BigInteger last = null;
    int mostCount = 0;
    int lastCount = 0;
    for (BigInteger x : list) {
        if (x.equals(last)) {
            lastCount++;
        } else if (lastCount > mostCount) {
            mostCount = lastCount;
            mostCommon = last;
        }
        last = x;
    }
    return mostCommon;
}

C’est un peu moins encombrant que d’utiliser un hachage pour compter, car cela trie le tableau en place. Vous pouvez lancer ceci dans une classe de génériques et remplacer BigInteger par T ou simplement utiliser Object à la place de BigInteger.

3
Alcanzar

Nous pouvons faire en une seule itération avec facilité:

public static Integer mostFrequent(List<Integer> list) {

    if (list == null || list.isEmpty())
        return null;

    Map<Integer, Integer> counterMap = new HashMap<Integer, Integer>();
    Integer maxValue = 0;
    Integer mostFrequentValue = null;

    for(Integer valueAsKey : list) {
        Integer counter = counterMap.get(valueAsKey);
        counterMap.put(valueAsKey, counter == null ? 1 : counter + 1);
        counter = counterMap.get(valueAsKey);
        if (counter > maxValue) {
            maxValue = counter;
            mostFrequentValue = valueAsKey;
        }
    }
    return mostFrequentValue;
}
1
Sandeep Sharda

Voici une extension de la réponse de Louis qui prend en charge le cas où plusieurs éléments ont le même nombre d'occurrences maximum:

private <T> List<T> getMostFrequentElements(List<T> list) {
    Multiset<T> multiset = HashMultiset.create(list);

    List<T> mostFrequents = new ArrayList<>();
    int maxCount = 0;

    for (Multiset.Entry<T> entry : multiset.entrySet()) {
        if (entry.getCount() > maxCount) {
            maxCount = entry.getCount();
            mostFrequents.clear();
            mostFrequents.add(entry.getElement());
        } else if (entry.getCount() == maxCount) {
            mostFrequents.add(entry.getElement());
        }
    }

    return mostFrequents;
}
1
a.b.d

Trouver l'élément le plus fréquent dans la collection:

private <V> V findMostFrequentItem(final Collection<V> items)
{
  return items.stream()
      .filter(Objects::nonNull)
      .collect(Collectors.groupingBy(Functions.identity(), Collectors.counting())).entrySet().stream()
      .max(Comparator.comparing(Entry::getValue))
      .map(Entry::getKey)
      .orElse(null);
}
0
nejckorasa

Si vous souhaitez utiliser Google Guava, vous pouvez utiliser ses classes MultiSet:

MultiSet<BigNumber> numbers = HashMultiSet.create();
numberSet.addAll(list);
Set<MultiSet.Entry<BigNumber>> pairs = numbers.emtrySet();
Set<MultiSet.Entry<BigNumber>> copies = new HashSet<MultiSet.Entry<BigNumber>>(pairs);

Maintenant, triez copies par ses valeurs décroissantes.

0
Eric Jablow