6
votes

Obtenez les chaînes qui se produisent exactement trois fois à partir de Arraylist

J'ai une ArrayList qui contient des valeurs avec des doublons et des éléments qui se produisent trois fois, je veux collecter ces valeurs qui se produisent trois fois spécifiquement dans un autre ArrayList comme

Arraylist<String> thrice;    //contains only elements that occur three times.

Ici, je veux obtenir uniquement les chaînes qui apparaissent trois fois dans une autre liste de tableaux.

Arraylist<String> strings;   //contains all strings that are duplicates and that occur thrice

Actuellement, j'ai un solution pour traiter les doublons mais je ne peut pas étendre cela pour obtenir uniquement des chaînes qui se produisent trois fois, veuillez m'aider à le découvrir.


3 commentaires

Fondamentalement, au lieu d'utiliser un HashSet , vous voulez maintenant utiliser un HashMap pour compter le nombre d'occurrences de chaque chaîne.


Voir cette réponse pour une solution comme @ shash678 suggéré


Double possible de obtenir les doublons valeurs de Arraylist , puis récupérez ces éléments dans une autre Arraylist


5 Réponses :


2
votes

En gros, au lieu d'utiliser un HashSet , vous souhaitez maintenant utiliser un HashMap pour compter le nombre d'occurrences de chaque chaîne.

De plus, au lieu d'écrire une méthode pour trouver les chaînes qui se produisent trois fois spécifiquement, vous pouvez écrire une méthode qui prend un paramètre, n et trouve les chaînes qui apparaissent N fois:

Original list: [a, b, c, d, e, b, c, c, d, d, d, e]
Strings that occur two times: [b, e]
Strings that occur three times: [c]
Strings that occur four times: [d]

Sortie:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

class StackOverflowQ {

  static List<String> getStringsThatOccurNTimes(List<String> stringList, int n) {
    if (stringList == null || stringList.size() == 0) {
      return stringList;
    }
    Set<String> stringsThatOccurNTimesSet = new HashSet<>();
    Map<String, Integer> stringCounts = new HashMap<>();
    for (String s : stringList) {
      int currentStringCount = stringCounts.getOrDefault(s, 0) + 1;
      stringCounts.put(s, currentStringCount);
      if (currentStringCount == n) {
        stringsThatOccurNTimesSet.add(s);
      } else if (currentStringCount == n + 1) {
        stringsThatOccurNTimesSet.remove(s); // We use a set so this operation is O(1)
      }
    }
    return new ArrayList<>(stringsThatOccurNTimesSet);
  }

  public static void main(String[] args) {
    List<String> stringsList = new ArrayList<>(Arrays.asList("a", "b", "c", "d", "e", "b", "c", "c", "d", "d", "d", "e"));
    List<String> stringsThatOccurTwoTimes = getStringsThatOccurNTimes(stringsList, 2);
    List<String> stringsThatOccurThreeTimes = getStringsThatOccurNTimes(stringsList, 3);
    List<String> stringsThatOccurFourTimes = getStringsThatOccurNTimes(stringsList, 4);
    System.out.println("Original list: " + stringsList);
    System.out.println("Strings that occur two times: " + stringsThatOccurTwoTimes);
    System.out.println("Strings that occur three times: " + stringsThatOccurThreeTimes);
    System.out.println("Strings that occur four times: " + stringsThatOccurFourTimes);
  }

}


2 commentaires

Comment un util pour cela en général?


Bien, j'utilise quelque chose de similaire en python lorsque je fais des questions d'entrevue similaires à celle d'OP.



3
votes

Vous pouvez le faire via un flux comme suit:

List<String> result = new HashSet<>(strings).stream()
                            .filter(item -> strings.stream()
                                  .filter(e -> e.equals(item)).limit(3).count() == 3)
                          .collect(Collectors.toList());

Vous pouvez également le faire comme suit, mais je recommanderais ce qui précède car c'est plus préférable.

 List<String> result = strings.stream()
                .collect(Collectors.groupingBy(Function.identity(), counting()))
                .entrySet().stream()
                .filter(e -> e.getValue() == 3) // keep only elements that occur 3 times
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());


2 commentaires

Le second ne semble pas vraiment efficace, il a une complexité temporelle O (n ^ 2) pour un problème qui se résout facilement en O (n), sorte de surpuissance.


@Ricola First est définitivement préférable. Je vais modifier pour le dire explicitement.



0
votes

Vous pouvez utiliser computeIfAbsent pour cela.

List<String> strings;

final Map<String, BigInteger> stringCounts = new HashMap<>();
strings.stream().forEach(s -> {
  BigInteger count = stringCounts.computeIfAbsent(s, k -> BigInteger.ZERO).add(BigInteger.ONE);
  stringCounts.put(s, count);
});

Filtrez maintenant stringCounts avec value = 3 .


0 commentaires

0
votes

Un utilitaire générique de ce que vous essayez de réaliser dans les deux questions consisterait à utiliser Collections.frequency as:

/**
 * @param input the list as your input
 * @param n     number of occurrence (duplicates :2 , triplets :3 etc)
 * @param <T>   (type of elements)
 * @return elements in a set
 */
static <T> Set<T> findElementsWithNOccurrence(List<T> input, int n) {
    return input.stream() // Stream<T>
            .collect(Collectors.groupingBy(Function.identity(), 
                    Collectors.counting())) // Map<T, Long>
            .entrySet() // Set<Map.Entry<T,Long>>
            .stream() // Stream<Map.Entry<T,Long>>
            .filter(e -> e.getValue() == n) // filtered with frequency 'n'
            .map(Map.Entry::getKey) // Stream<T>
            .collect(Collectors.toSet()); // collect to Set
}

Remarque : Ce serait une approche O(n^2) car il utilise Collections.frequency qui itère à nouveau sur toute la collection pour obtenir la fréquence. Mais proposé pour une approche plus lisible et générique de ce que vous recherchez. En outre, cela collecte intentionnellement la sortie finale vers un Set , car une List peut à nouveau avoir des doublons après tout.


Alternativement, vous pouvez utiliser la méthode pour compter la fréquence des éléments en Java-8 et parcourir les entrées du code Map > créé ainsi pour traiter le filtrage comme vous le souhaitez et collecter la sortie dans la même itération:

/**
 * @param input the list as your input
 * @param n number of occurrence (duplicates:2 , triplets:3 etc..)
 * @param <T> (type of elements)
 * @return elements with such conditional occurrent in a Set
 */
static <T> Set<T> findElementsWithNOccurrence(List<T> input, int n) {
    return input.stream()
            .filter(a -> Collections.frequency(input, a) == n) // filter by number of occurrences
            .collect(Collectors.toSet()); // collecting to a final set (one representation of each)
}


0 commentaires

1
votes

La meilleure façon de faire est de .....

Création de la liste d'arrays requise .........

                           if(entry.getValue()>=3){
                             thrice.add(entry.getKey());
                           }

Ajout de valeurs pour vérification .......

    ArrayAdapter<String> ad=new ArrayAdapter<> 
    (this,android.R.layout.simple_list_item_1,thrice);
    ListView lv=findViewById(R.id.new_l);
    lv.setAdapter(ad);

Mappage pour terminer la tâche .....

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

    for (String str : one) {
        if (duplicates.containsKey(str)) {
            duplicates.put(str, duplicates.get(str) + 1);
        } else {
            duplicates.put(str, 1);
        }
    }

    for (Map.Entry<String, Integer> entry : duplicates.entrySet()) {

                       if(entry.getValue()>=3){
                             thrice.add(entry.getKey());
                           }
    }

Définissez le list in listview ...

    one.add("1");one.add("1");one.add("1");one.add("1");one.add("1");
    one.add("2");one.add("2");one.add("2");one.add("2");one.add("2");
    one.add("1");one.add("1");one.add("1");
    one.add("3");one.add("3");
    one.add("4");one.add("5");
    one.add("2");one.add("2");one.add("2");

Output = 1,2

Vérifiez déjà la réponse et vous pouvez changer la condition selon votre chemin p >

    ArrayList<String> thrice=new ArrayList<>();
    ArrayList<String> one=new ArrayList<>();

Réponse la plus simple ci-dessus ... pas nécessaire pour changer les versions du sdk minimum pour l'utilisateur Android


0 commentaires