views:

355

answers:

5

Edit: My list is sorted as it is coming from a DB I have an ArrayList that has objects of class People. People has two properties: ssn and terminationReason. So my list looks like this

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

I want to change this list up so that there are no duplicates and termination reasons are seperated by commas.

so above list would become

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

I have something going where I am looping through the original list and matching ssn's but it does not seem to work.

Can someone help?

Code I was using was:

    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()
       }
    }
+3  A: 
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;
}

And you get the aggregated list in newlst.

Update: If you are using MySQL, you can use the GROUP_CONCAT function to extract data in your required format. I don't know whether other DB engines have similar function or not.

Update 2: Removed the unnecessary sorting.

kd304
+3  A: 

What you might need is a Hash. HashMap maybe usable.

Override equals() and hashCode() inside your People Class.

Make hashCode return the people (person) SSN. This way you will have all People objects with the same SSN in the same "bucket".

Keep in mind that the Map interface implementation classes use key/value pairs for holding your objects so you will have something like myHashMap.add("ssn",peopleobject);

andreas
+1  A: 

Two possible problems:

  • This won't work if your list isn't sorted
  • You aren't doing anything with ob.getTerminationReason(). I think you mean to add it to the previous object.
stevedbrown
A: 

EDIT: Now that i see you´ve edited your question.

As your list is sorted, (by ssn I presume)

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.
 }

}

If you don´t want to display the contents of your list, you could use it to create a MAP and then use it as shown below.

If your list is not sorted

Maybe you should try a different approach, using a Map. Here, ssn would be the key of the map, and values could be a list of People

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, you should override your hashCode() and equals() method on People class.

for example

public void int hashcode(){

  return 3*this.reason.hascode();

}
Tom
in your solution for sorted list..where will I add the person object to the newlist? If I add it in the 'else' then I will need to somehow updated the object in 'if'...
+4  A: 

To me, this seems like a good case to use a Multimap, which would allow storing multiple values for a single key.

The Google Collections has a Multimap implementation.

This may mean that the Person object's ssn and terminationReason fields may have to be taken out to be a key and value, respectively. (And those fields will be assumed to be String.)

Basically, it can be used as follows:

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.
}

If necessary, a comma-separated list of a Collection can be produced:

StringBuilder sb = new StringBuilder();

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

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

This could once again be set to the terminationReason field.

An alternative, as Jonik mentioned in the comments, is to use the StringUtils.join method from Apache Commons Lang could be used to create a comma-separated list.

It should also be noted that the Multimap doesn't specify whether an implementation should or should not allow duplicate key/value pairs, so one should look at which type of Multimap to use.

In this example, the HashMultimap is a good choice, as it does not allow duplicate key/value pairs. This would automatically eliminate any duplicate reasons given for one specific person.

coobird
+1 Exactly. I was about to post my own Multimap answer, but I'll skip that now. :) Although I'd use StringUtils.join() from Apache Commons Lang for the comma-separated list. (And mention that perhaps the object-relational mapping could be reconsidered in general - an object in Java representing a person should have all the reasons in it...)
Jonik
@Jonik, thank you for your pointer on StringUtils.join :) I've added that to the answer. (I knew there had to be a better way than doing it by hand.) Also, I also agree that the Person object itself should hold multiple reasons than having multiple Person objects for one person.
coobird