0

Requirement -

I have a list of objects as given below -

[
TestObj{levelCode='123', operId='ABC', hrchyInd='S'},
TestObj{levelCode='456', operId='DEF', hrchyInd='S'},
TestObj{levelCode='123', operId='ABC', hrchyInd='M'}
]

My desired output is -

[
TestObj{levelCode='123', operId='ABC', hrchyInd='B'},
TestObj{levelCode='456', operId='DEF', hrchyInd='S'},
]

If two TestObj in the list are having the same levelCode && OperId but different hrchyInd then we should include only one TestObj out of the two in the output list and modify the hrchyInd as B.

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.ToString;

@Data
@AllArgsConstructor
@ToString
@Builder
public class TestObj {
    private String levelCode;
    
    private String operId;
    
    private String hrchyInd;
}

Can anyone please help me to solve this problem in an optimal way.

2
  • 1
    You should indicate the source of your annotations. If not relevant, delete them from your Question. Commented Dec 28, 2021 at 6:50
  • 1
    Please include the code you have tried. Commented Dec 28, 2021 at 6:54

5 Answers 5

1

Thank you all specially Basil Bourque, for your quick replies and suggestions, it helped me a lot to come up with a solution for the problem.

Please let me know if any way this can be improved even further.

Step 1 - Overriding the equals() and hashCode() methods in my TestObj class

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.ToString;

@Data
@AllArgsConstructor
@ToString
@Builder
public class TestObj {
    private String levelCode;
    
    private String operId;
    
    private String hrchyInd;

    @Override
    public int hashCode() {
        return Objects.hash(this.getLevelCode(), this.getOperId());
    }

    @Override
    public boolean equals(Object obj) {
        TestObj testObj= (TestObj) obj;
        return testObj.getLevelCode().equals(this.getLevelCode()) &&
                testObj.getOperId().equals(this.getOperId());
    }
}

Step 2 - Adding all TestObj in to a Set, while adding checking if the object is already present or not, if present then update that object with hrchyInd = "B" and replace the object in the Set.

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class TestClass {
    public static void main(String[] args) {
        List<TestObj> hrchyList = new ArrayList<>();
        Set<TestObj> hrchySet = new HashSet<>();

        hrchyList.add(new TestObj("123", "ABC", "M"));
        hrchyList.add(new TestObj("456", "DEF", "S"));
        hrchyList.add(new TestObj("123", "ABC", "S"));

        hrchyList.forEach(testObj -> {
            if(hrchySet.contains(testObj)) { // Checking for duplicates
                testObj.setHrchyInd("B"); // Update the testObj with hrchyInd = "B"
                // Replacing the object in the Set
                hrchySet.remove(testObj);
                hrchySet.add(testObj);
            }
            else {
                hrchySet.add(testObj);
            }
        });

        System.out.println(hrchySet);
    }
}

Output -

[
TestObj{levelCode='456', operId='DEF', hrchyInd='S'}, 
TestObj{levelCode='123', operId='ABC', hrchyInd='B'}
]
Sign up to request clarification or add additional context in comments.

Comments

1

I cannot speak to Lombok, as I’ve never used it. Otherwise, here is what I would do.


Override equals and hashCode to consider the two member fields, levelCode and operId, but not hrchyInd.

When adding to your list or set, first test if the collection contains said item. If not, proceed with adding. If found, change the hrchyInd field value of additional item to B, and replace existing item.

1 Comment

Thank you for the idea, properly implementing hashCode and equals methods helped me to solve this problem in a cleaner way. Posting the solution below for the reference.
0

Few suggestions to accomplish this:

  1. Since you are dealing with custom objects and not literals, first thing is override equals() method of the TestObj class. Make sure that you check the appropriate equality.
  2. Add all such objects to a collection (ArrayList for example)
  3. From here either you can create a Set (HashSet) from the list or use Stream distinct method to filter out the duplicates.

Comments

0
public static TestObj[] addNewTest(TestObj[] oldArray, TestObj newTest)
{
  TestObj[] response = new TestObj[oldArray.length + 1];
  for(int  i = 0; i < response.length - 1; i++)
  {
    response[i] = oldArray[i];
  }
  response[response.length - 1] = newTest;
  return response;
}

public static TestObj[] filterTestObjects(TestObj[] testObjects)
{
   TestObj[] response = new TestObj[0];
   boolean  isExists  = false;
   
   for(int  i = 0; i < testObjects.length; i++)
   {
     isExists = false;
     for(int j = 0; j < response.length; j++)
     {
       if(i!=j && response[j].levelCode == testObjects[i].levelCode && response[j].operId == testObjects[i].operId)
       {
         isExists = true;
         break;
       }
     }
     if(!isExists)
     {
       response = addNewTest(response, testObjects[i]);
     }
   }
   return response;
}

public static Object[][] someMagic(Object[] suite, Object[] rank) {
    Object[][] retVal = new Object[suite.length * rank.length][2];
    int i = 0;
    for (Object s : suite) {
        for (Object r : rank) {
            retVal[i++] = new Object[]{r, s};
        }
    }
    return retVal;
}

public static void printTestArray(TestObj[] testObjects)
{
   for(int  i = 0; i < testObjects.length; i++)
   {
     System.out.println(testObjects[i].levelCode + testObjects[i].operId + testObjects[i].hrchyInd);
   }
}

public static void main(String[] args) {
  TestObj t1 = new TestObj("123", "ABC", "S");
  TestObj t2 = new TestObj("456", "DEF", "S");
  TestObj t3 = new TestObj("123", "ABC", "M");  
  
  TestObj[] testObjects = {t1, t2, t3};
  testObjects = filterTestObjects(testObjects);
  printTestArray(testObjects);
}

2 Comments

Output : 123ABCS 456DEFS
hello, you can do your job with a filtering function in this way.
0

Here Stream API and Collectors.toMap with the merge function may be used to resolve this task.

Merge function is needed to set "B" value when multiple issues are detected.

The key for the function may be implemented as a List<String> or (in Java 16+) as a record. Thus, in either case the existing TestObj class remains as is and its hashCode/equals do not need overriding:

List<TestObj> input = Arrays.asList(
        new TestObj("123", "ABC", "M"),
        new TestObj("456", "DEF", "S"),
        new TestObj("123", "ABC", "S")
);

List<TestObj> result = new ArrayList<>(input.stream()
    .collect(Collectors.toMap(
        x -> Arrays.asList(x.getLevelCode(), x.getOperId()), // key
        Function.identity(), // value - the TestObj instance itself
        (t1, t2) -> { t1.setHrchyInd("B"); return t1; },
        LinkedHashMap::new // keep insertion order
    )) // Map<List<String>, TestObj>
    .values() // Collection<TestObj>
);
result.forEach(System.out::println);

Output:

TestObj(levelCode=123, operId=ABC, hrchyInd=B)
TestObj(levelCode=456, operId=DEF, hrchyInd=S)

An example using record GroupBy (for Java 16+) and Collectors.collectingAndThen.

Also, if Lombok @Accessors(chain = true) is applied to TestObj class so that the setters return current object, the merge function could be simplified:

record GroupBy(String levelCode, String operId) {}

List<TestObj> input = ... // create/populate input list
List<TestObj> result = input.stream()
    .collect(Collectors.collectingAndThen(
        Collectors.toMap(
            x -> new GroupBy(x.getLevelCode(), x.getOperId()), // key
            Function.identity(), // value - the TestObj instance itself
            (t1, t2) -> t1.setHrchyInd("B"), // setHrchyInd returns this
            LinkedHashMap::new // keep insertion order
        ), // Map<GroupBy, TestObj>
        map -> new ArrayList<>(map.values())
    ));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.