Home > Mobile >  Why this algoritm with recursion gaves duplicates in result? The result should contain only unique e
Why this algoritm with recursion gaves duplicates in result? The result should contain only unique e

Time:06-03

I try to make function which excludes the same elements from list. The result should be unique elements in list like [a, d, b, c] or in different order it doesnt matter. The below code on not small source data gaves wrong result. For instance,

[a, d, a, a, b, b, c]
::::::::::
------ignore element-------
removed a
------ignore element-------
removed a
------ignore element-------
removed a
------ignore element-------
[a, d, b, b, c]

the code

public class Test {
    String s;
    public Test(String s) {
        this.s = s;
    }

    @Override
    public String toString() {
        return s;
    }

    public static void main(String[] args) {
        ArrayList<Test> arr = new ArrayList<>();
        arr.add(new Test("a"));
        arr.add(new Test("d"));
        arr.add(new Test("a"));
        arr.add(new Test("a"));
        arr.add(new Test("b"));
        arr.add(new Test("b"));
        arr.add(new Test("c"));
        System.out.println(arr);
        System.out.println("::::::::::");
        System.out.println(compare(arr));
    }

    static private ArrayList<Test> compare(ArrayList<Test> arr) {
        ArrayList<Test> result = new ArrayList<>(arr);
        for (Test valueToCompare : arr) {
            for (Test t : arr) {
                if((valueToCompare.s).equals(t.s)) {
                    
                    if(valueToCompare == t) {
                        // it's the same obj
                        System.out.println("------ignore element-------");
                        continue;
                    }
                    // it's identical values and diffrent objects so removing it from result array
                    result.remove(t);
                    System.out.println("removed "   t.s);
                    compare(result); // recursion
                }
            }
            break;
        }
        return result;
    }
}

I know about set and related things so please do not sugest it. It shoud be done in a separate function. How to fix this function to recive correct result?

CodePudding user response:

If the list is not huge or memory is not an issue, you can use LinkedHashSet class, which removes the duplicates and maintain the order.
If you care about the order, you can just go with the HashSet class.

Sample code ::

import java.util.*;

public class RemoveDuplicates {

    String s;

    public RemoveDuplicates(String s) {
        this.s = s;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        RemoveDuplicates that = (RemoveDuplicates) o;
        return Objects.equals(s, that.s);
    }

    @Override
    public int hashCode() {
        return Objects.hash(s);
    }

    @Override
    public String toString() {
        return s;
    }

    public static void main(String[] args) {
        List<RemoveDuplicates> arr = new ArrayList<>();
        arr.add(new RemoveDuplicates("a"));
        arr.add(new RemoveDuplicates("d"));
        arr.add(new RemoveDuplicates("a"));
        arr.add(new RemoveDuplicates("a"));
        arr.add(new RemoveDuplicates("b"));
        arr.add(new RemoveDuplicates("b"));
        arr.add(new RemoveDuplicates("c"));

        removeDuplicates(arr);

        System.out.println(arr);
    }

    private static void removeDuplicates(List<RemoveDuplicates> arr) {
        Set<RemoveDuplicates> duplicatesRemoved = new LinkedHashSet<>(arr); // [#1]
        arr.clear();                           // [#2]
        arr.addAll(duplicatesRemoved);         // [#3]
    }
}

PS. #1. Constructor used to create a new Set from the list given. The catch, Sets uses @equals() method to compare objects, if the equals() method is not overrided, the flow won't work.
#2 & #3. Just to store back the results in the same list. If type is not an issue, just return the Set and use further without clearing and reset the list.

Edit:: Method 2 to remove duplicates

private static List<RemoveDuplicates> removeDuplicatesMethod2(List<RemoveDuplicates> arr) {
     return arr.stream()
             .distinct()
             .collect(Collectors.toList());
}

Uses Java streams to remove duplicates and create new List. Return the list and use it further.

CodePudding user response:

The problem is the "break statement" which always breaks the loop.

Your algorithm works like this.

Step1 -> take "a" (first element) and check for duplicate.

Step2 -> Since there is duplicate the function is called recursively until all duplicates of "a" is removed.

Step3 -> Now reaches the break statement and terminates.

This algorithm is very complex.

I suggest you to use this algorithm

private static ArrayList<Test> compare(ArrayList<Test> list)
{

    // Create a new ArrayList
    ArrayList<Test> newList = new ArrayList<Test>();

    // Traverse through the first list
    for (Test element : list) {

        // If this element is not present in newList
        // then add it
        if (!newList.contains(element)) {

            newList.add(element);
        }
    }

    // return the new list
    return newList;
}

Hope this helps you :).

  •  Tags:  
  • java
  • Related