7 votes

Comment ajouter et supprimer des objets répétés dans ArrayList ?

Modèle de détail de l'utilisateur :

private String userName;
private int userSalary;

J'ai une liste d'informations sur les utilisateurs.

List<UserDetail> userDetails = new ArrayList<>();

UserDetail user1 = new UserDetail("Robert", 100);
UserDetail user2 = new UserDetail("John", 100);
UserDetail user3 = new UserDetail("Robert", 55);

userdetails.add(user1);
userdetails.add(user2);
userdetails.add(user3);

J'essaie d'itérer à travers le tableau et de trouver s'il y a des entrées en double en fonction des critères suivants userName Dans la liste ci-dessus, j'ai deux enregistrements avec le même nom d'utilisateur. "Robert" dans ce cas, je veux ajouter les userSalary et supprimer un enregistrement de la liste.

Attente d'une nouvelle ArrayList :

userName userSalary

Robert 155
John 100

Est-ce possible ?

2voto

Eugene Points 6271
 userDetails.stream()
            .collect(Collectors.toMap(
                        UserDetail::getName,
                        Function.identity(),
                        (left, right) -> {
                            left.setSalary(left.getSalary() + right.getSalary());
                            return left;
                        }
                    ))
            .values();

Cela vous donnera un Collection<UserDetail> . Vous pouvez le copier dans un ArrayList si nécessaire, évidemment.

1voto

Jacob G. Points 16099

Parce que votre but est de regrouper UserDetail qui partagent le même userName je recommande de stocker le résultat dans un fichier Map au lieu d'un ArrayList .

Cela est possible en diffusant votre List et le collecter vers un Map en utilisant Collectors#groupingBy en collaboration avec Collectors#summingInt :

List<UserDetail> userDetails = new ArrayList<>();

UserDetail user1 = new UserDetail("Robert", 100);
UserDetail user2 = new UserDetail("John", 100);
UserDetail user3 = new UserDetail("Robert", 55);

userDetails.add(user1);
userDetails.add(user2);
userDetails.add(user3);

Map<String, Integer> groupedUserDetails = userDetails.stream()
    .collect(Collectors.groupingBy(UserDetail::getUserName,
        Collectors.summingInt(UserDetail::getUserSalary)));

System.out.println(groupedUserDetails);

L'extrait ci-dessus peut donner le résultat suivant :

{Robert=155, John=100}

Si vous voulez convertir cette Map<String, Integer> en un List<UserDetail> vous pouvez alors utiliser la méthode suivante :

List<UserDetail> newUserDetails = groupedUserDetails.entrySet()
    .stream()
    .map(entry -> new UserDetail(entry.getKey(), entry.getValue())
    .collect(Collectors.toList());

1voto

dan1st Points 6488

Voici une solution sans flux (peut-être plus facile à comprendre) :

Iterator<UserDetail> it=userDetails.iterator();
Map<String,UserDetail> found=new HashMap<>();
while(it.hasNext()){
    UserDetail next=it.next();
    if(found.containsKey(next.getUserName())){
        found.get(next.getUserName()).setUserSalery(found.get(next.getUserName()).getUserSalery()+next.getUserSalery();
        it.remove();
    }
    else{
        found.put(next.getUserName(),next);
    }
}

Cela permet d'itérer à travers tous les éléments.

S'il a déjà trouvé un élément correspondant, il y ajoute sa propre salade et se retire de la liste.

Sinon, il se marque lui-même pour être trouvé si d'autres éléments sont trouvés avec le même nom plus tard.

Cela suppose que UserDetail possède des méthodes standard de récupération et de modification des données pour userName y userSalery .

Notez qu'une boucle for-each ne peut pas être utilisée parce que vous ne pouvez pas modifier le contenu de la liste dans cette boucle (cela déclencherait une erreur de type ConcurrentModificationException ).

D'après les commentaires(de @ Holger :

Vous pouvez utiliser un seul UserDetail previous = found.putIfAbsent(next.getName()); suivi par if(previous != null) { previous.setSalery(previous.getSalery()+next.getSalery()); it.remove(); } au lieu de chercher la carte trois fois de suite.

Ce code serait :

Iterator<UserDetail> it=userDetails.iterator();
Map<String,UserDetail> found=new HashMap<>();
while(it.hasNext()){
    UserDetail next=it.next();
    UserDetail previous = found.putIfAbsent(next.getUserName());
    if(previous != null) {
        previous.setUserSalery(previous.getUserSalery()+next.getUserSalery());
        it.remove();
    }
}

Cela fait essentiellement la même chose.

Il ajoute l'élément actuel à la liste s'il n'existe pas et sinon, il additionne simplement la saleté.

0voto

Aditya Rewari Points 1131

Je peux suggérer une autre approche. HashMap

  • Utiliser le nom d'utilisateur comme clé
  • remplacer equals & hashcode
  • Avant d'ajouter un élément à la hashMap, vérifier si un objet est déjà présent
  • Si l'objet est trouvé, on récupère son salaire, on met à jour l'objet actuel, puis on l'ajoute à la carte.

public class UserDetail {
    private String userName;
    private int userSalary;

    @Override
    public boolean equals(Object obj) {
        return this.userName.equals(((UserDetail)obj).userName);
    }

    @Override
    public int hashCode() {
        return userName.length();
    }
}

0voto

lakshman Points 1649

Aquí Map est utilisé pour stocker UserDetail par userName . Si l'utilisateur est dans la carte, le salaire sera ajouté et mis à jour dans la carte. Dans le cas contraire, l'utilisateur sera placé dans la carte. Enfin, les valeurs de la carte seront converties en un UserDetail liste

Map<String, UserDetail> mergedMap = new HashMap<>(); // username is used as the key 
userDetails.forEach(userDetail -> {
   String userName = userDetail.getUserName();
   UserDetail userInMap = mergedMap.get(userName);
   if (userInMap != null) { // if user is in map salary will be added
      userInMap.setUserSalary(userInMap.getUserSalary() + userDetail.getUserSalary());
   } else { //otherwise user will put in map
      mergedMap.put(userDetail.getUserName(), userDetail);
   }
});

List<UserDetail> usersWithMergedSalaries = new ArrayList<>(mergedMap.values()); //convert map values to a list

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X