2009-06-21 12 views
2

Editer: Ma liste est triée comme elle vient d'un DB J'ai une ArrayList qui a des objets de la classe People. Les personnes ont deux propriétés: ssn et terminationReason. Donc ma liste ressemble à cecicomment manipuler la liste dans java

ArrayList: 
ssn   TerminatinoReason 
123456789  Reason1 
123456789  Reason2 
123456789  Reason3 
568956899  Reason2 
000000001  Reason3 
000000001  Reason2 

Je souhaite modifier cette liste afin qu'il n'y ait pas de doublons et les raisons de résiliation sont séparés par des virgules.

liste ci-dessus deviendrait donc

New ArrayList: 
ssn   TerminatinoReason 
123456789  Reason1, Reason2, Reason3 
568956899  Reason2 
000000001  Reason3, Reason2 

J'ai quelque chose où je suis Boucler dans la liste semble originale et correspondant à des années ssn, mais il ne fonctionne pas.

Quelqu'un peut-il aider?

code j'utilisais était:

String ssn = ""; 
    Iterator it = results.iterator(); 
    ArrayList newList = new ArrayList(); 
    People ob; 
    while (it.hasNext()) 
    { 
     ob = (People) it.next(); 
     if (ssn.equalsIgnoreCase("")) 
     { 
      newList.add(ob); 
      ssn = ob.getSSN(); 
     } 
     else if (ssn.equalsIgnoreCase(ob.getSSN())) 
     { 
      //should I get last object from new list and append this termination reason? 
      ob.getTerminationReason() 
     } 
    } 
+1

pouvez-vous afficher le code dans lequel vous parcourez la liste? – rogeriopvl

+0

J'ai ajouté le code où je suis en boucle dans la liste –

+0

Vous pouvez laisser la requête de base de données supprimer les dups afin que vous n'ayez pas à les traiter dans votre code java. Généralement, tout ce que vous faites dans la base de données sera probablement beaucoup plus efficace. – rich

Répondre

3
List<People> newlst = new ArrayList<People>(); 
People last = null; 
for (People p : listFromDB) { 
    if (last == null || !last.ssn.equals(p.ssn)) { 
     last = new People(); 
     last.ssn = p.ssn; 
     last.terminationReason = ""; 
     newlst.add(last); 
    } 
    if (last.terminationReason.length() > 0) { 
     last.terminationReason += ", "; 
    } 
    last.terminationReason += p.terminationReason; 
} 

Et vous obtenez la liste agrégée en newlst.

Mise à jour: Si vous utilisez MySQL, vous pouvez utiliser la fonction GROUP_CONCAT pour extraire des données dans le format requis. Je ne sais pas si d'autres moteurs DB ont une fonction similaire ou non.

Mise à jour 2: Removed le tri inutile.

3

Ce que vous pourriez avoir besoin est un hachage. HashMap peut être utilisable.

Substituez equals() et hashCode() dans votre classe People.

Faites en sorte que hashCode renvoie les personnes (personnes) SSN. De cette façon, vous aurez tous les objets People avec le même SSN dans le même "seau". Gardez à l'esprit que les classes d'implémentation de l'interface Map utilisent des paires clé/valeur pour contenir vos objets afin que vous ayez quelque chose comme myHashMap.add ("ssn", peopleobject);

1

Deux problèmes possibles:

  • Cela ne fonctionnera pas si votre liste ne sont pas triées
  • Vous ne faites rien avec ob.getTerminationReason(). Je pense que vous voulez l'ajouter à l'objet précédent.
0

EDIT: Maintenant que je vois que vous avez modifié votre question.

En tant que votre liste est triée, (par ssn je présume)

Integer currentSSN = null; 
List<People> peoplelist = getSortedList();//gets sorted list from DB. 
/*Uses foreach construct instead of iterators*/ 

for (People person:peopleList){ 

if (currentSSN != null && people.getSSN().equals(currentSSN)){ 
//same person 
system.out.print(person.getReason()+" ");//writes termination reason 

} 
else{//person has changed. New row. 
    currentSSN = person.getSSN(); 
    system.out.println(" ");//new row. 
    system.out.print(person.getSSN()+ " ");//writes row header. 
} 

} 

Si vous ne voulez pas afficher le contenu de votre liste, vous pouvez l'utiliser pour créer une carte, puis l'utiliser comme indiqué ci-dessous.

Si votre liste ne sont pas triées

Peut-être que vous devriez essayer une approche différente, en utilisant une carte. Ici, ssn serait la clé de la carte, et les valeurs pourrait être une liste de personnes

méthode
Map<Integer,List<People>> mymap = getMap();//loads a Map from input data. 

for(Integer ssn:mymap.keyset()){ 
dorow(ssn,mymap.get(ssn)); 
} 

public void dorow(Integer ssn, List<People> reasons){ 

system.out.print(ssn+" "); 
for (People people:reasons){ 
system.out.print(people.getTerminationReason()+" "); 
} 

system.out.println("-----");//row separator. 

Last but not least, vous devriez passer outre votre hashCode() et equals() de la classe de personnes.

par exemple

public void int hashcode(){ 

    return 3*this.reason.hascode(); 

} 
+0

dans votre solution pour la liste triée ... où vais-je ajouter l'objet personne à la nouvelle liste? Si je l'ajoute dans le 'else' alors je devrai mettre à jour l'objet dans 'if' ... –

5

Pour moi, cela semble être un bon exemple d'utiliser un Multimap, qui permettrait le stockage de valeurs multiples pour une seule clé.

Le Google Collections a une implémentation Multimap.

Cela peut signifier que les champs de l'objet ssn et terminationReason doivent être retirés pour être une clé et une valeur, respectivement. (Et ces champs seront supposés être String.)

Fondamentalement, il peut être utilisé comme suit:

Multimap<String, String> m = HashMultimap.create(); 

// In reality, the following would probably be iterating over the 
// Person objects returned from the database, and calling the 
// getSSN and getTerminationReasons methods. 

m.put("0000001", "Reason1"); 
m.put("0000001", "Reason2"); 
m.put("0000001", "Reason3"); 
m.put("0000002", "Reason1"); 
m.put("0000002", "Reason2"); 
m.put("0000002", "Reason3"); 

for (String ssn : m.keySet()) 
{ 
    // For each SSN, the termination reasons can be retrieved. 
    Collection<String> termReasonsList = m.get(ssn); 

    // Do something with the list of reasons. 
} 

Si nécessaire, une liste séparée par des virgules d'un Collection peut être produit:

StringBuilder sb = new StringBuilder(); 

for (String reason : termReasonsList) 
{ 
    sb.append(reason); 
    sb.append(", "); 
} 

sb.delete(sb.length() - 2, sb.length()); 
String commaSepList = sb.toString(); 

Ceci peut à nouveau être défini sur le champ terminationReason.

Une alternative, comme Jonik mentionné dans les commentaires, est d'utiliser la méthode StringUtils.join de Apache Commons Lang qui pourrait être utilisée pour créer une liste séparée par des virgules.

Il convient également de noter que le Multimap ne précise pas si une mise en œuvre doit ou non permettre à des paires en double clé/valeur, donc il faut regarder quel type de Multimap à utiliser.

Dans cet exemple, le HashMultimap est un bon choix, car il n'autorise pas les paires clé/valeur en double. Cela éliminerait automatiquement toutes les raisons en double données pour une personne spécifique.

+0

+1 Exactement. J'étais sur le point de poster ma propre réponse Multimap, mais je vais passer cela maintenant. :) Bien que j'utiliserais StringUtils.join() d'Apache Commons Lang pour la liste séparée par des virgules. (Et mentionne que peut-être le mapping objet-relationnel pourrait être reconsidéré en général - un objet en Java représentant une personne devrait avoir toutes les raisons dedans ...) – Jonik

+0

@Jonik, merci pour ton pointeur sur StringUtils.join :) I J'ai ajouté cela à la réponse. (Je savais qu'il devait y avoir un meilleur moyen que de le faire à la main.De plus, je suis également d'accord pour dire que l'objet Personne lui-même devrait avoir plusieurs raisons d'avoir plusieurs objets Personne pour une personne. – coobird