Home > Mobile >  Compare two Objects in a List and make it as one Object if any Duplicates
Compare two Objects in a List and make it as one Object if any Duplicates

Time:08-18

I have ArrayList of objects

public static void prepareList() {      
    
    Author a1 =new Author();
    Author a2 =new Author();
    Author a3 =new Author();
    Author a4 =new Author();
    Author a5 =new Author();
    Author a6 =new Author();
    Author a7 =new Author();        
    
    a1.setTransId("1111111");
    a1.setCountryCode("US");
    a1.setCurrencyUSD(100000);
    a1.setExccessAmount(100000);
    
    a2.setTransId("1111111");
    a2.setCountryCode("US");
    a2.setCurrencyUSD(100000);
    a2.setExccessAmount(100000);
    
    a3.setTransId("1111111");
    a3.setCountryCode("IN");
    a3.setCurrencyUSD(100000);
    a3.setExccessAmount(100000);
    
    a4.setTransId("222222");
    a4.setCountryCode("US");
    a4.setCurrencyUSD(100000);
    a4.setExccessAmount(100000);
    
    a5.setTransId("222222");
    a5.setCountryCode("US");
    a5.setCurrencyUSD(100000);
    a5.setExccessAmount(100000);
    
    a6.setTransId("3333333");
    a6.setCountryCode("US");
    a6.setCurrencyUSD(100000);
    a6.setExccessAmount(100000);
    
    a7.setTransId("444444");
    a7.setCountryCode("US");
    a7.setCurrencyUSD(100000);
    a7.setExccessAmount(100000);
    
    
    Collection<Author> arrayListofObjects = new ArrayList<Author>();

    arrayListofObjects.add(a1);
    arrayListofObjects.add(a2);
    arrayListofObjects.add(a3);
    arrayListofObjects.add(a4);
    arrayListofObjects.add(a5);
    arrayListofObjects.add(a6);
    arrayListofObjects.add(a7);
    
    System.out.println("arrayListofObjects Size = "   arrayListofObjects.size());
    Map<String, List<Author>> mapList = arrayListofObjects.stream().collect(Collectors.groupingBy(authorObj -> authorObj.getTransId() "_" 
            authorObj.getCountryCode()));
    System.out.println("Map Size = "   mapList.size());
    for(Entry<String, List<Author>> listobj : mapList.entrySet()) {
        String key = listobj.getKey();
        //System.out.println("key = "   key);
        List<Author> contraList = mapList.get(key);
        //System.out.println("contraList = "   contraList.size());
        //TODO if the list size is >1 then add CurrencyUSD and ExccessAmount, make as one object in that list (Size should be 1)
        if(contraList.size()>1) {
            System.out.println("key = "   key);
            System.out.println("contraList = "   contraList.size());
        }
    }

Here a1,a2 and a4,a5 are having same TransId, CountryCode I want to make them one obj adding CurrencyUSD, ExccessAmount achieving less time consuming way as I will be dealing with large data. Maybe using comparator, Streams.

I see one similar question but its time consuming not working as expected.

CodePudding user response:

You were in the right track by grouping, just add a reducing collector:

Map<String, Author> mapList =
        arrayListofObjects.stream()
                          .collect(Collectors.groupingBy(authorObj -> authorObj.getTransId()   "_"   authorObj.getCountryCode(),
                                                         Collectors.reducing(new Author("", "", 0, 0),
                                                                             (x,y) -> {
                                                             y.setCurrencyUSD(y.currencyUSD   x.currencyUSD);
                                                             y.setExccessAmount(y.exccessAmount   x.exccessAmount);
                                                             return y;
                                                         })));

final Collection<Author> aggregated = new ArrayList<>(mapList.values());

CodePudding user response:

Another way can be

List<Author> out = arrayListofObjects.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toMap(e->e.getTransId() e.getCountryCode(), Function.identity(), (a, b) -> {                         
                                a.setCurrencyUSD(a.getCurrencyUSD() b.getCurrencyUSD());
                                a.setExccessAmount(a.getExccessAmount() b.getExccessAmount());
                            return a;
                        }), m -> new ArrayList<>(m.values())));
out.forEach(System.out::println);

CodePudding user response:

For comparison, I'll also add a version not using streams:

//map of unquie authors based on transid and country code, keep order of authors as per the list
Map<String, Author> uniqueAuthors = new LinkedHashMap<>(); 

//iterate over the incoming list of authors
for( Author author : arrayListofObjects ) {
  //get the author based on "<transid>_<country_code>"
  //if the author doesn't exist create a new copy using the incoming key and 0 values
  Author uniqueAuthor = uniqueAuthors .computeIfAbsent(author.getTransId()   "_"   author.getCountryCode(),
    key -> new Author(author.getTransId(), author.getCountryCode(), 0,0 );

  //add the currency into the unique author
  uniqueAuthor.setCurrencyUSD(uniqueAuthor.getCurrencyUSD()   author.getCurrencyUSD());
  //add the excess amount into the unique author
  uniqueAuthor.setExccessAmount(uniqueAuthor.getExccessAmount()   author.getExccessAmount());
}

//create a list of unique authors that keeps the original ordering
List<Author> listOfUniqueAuthors = new ArrayList<>(uniqueAuthors.values());

Quick description of this approach:

  • LinkedHashMap keeps the order of insertion and thus would help to get authors in the order in which they appeared in the original list (based on first appearance)
  • computeIfAbsent() executes the lambda if there is no value for the given key and adds it to the map, otherwise just returns the existing value
  • the lambda is used to create a new author with the same trans id and country code so we don't change the original elements
  • we add the values of the current author from the list into the unique author from the map - if this is a new copy we'll just add the values to 0
  •  Tags:  
  • java
  • Related