0

This is a 2 part question 1st the question asks to create a method to check whether two sequences have the same values in the same order.

Secondly the bit I'm stuck on the question asks to create a method to check whether two sequences have the same values in some order, ignoring duplicates ie Sequence 1 (1, 4, 9, 16, 9, 7, 4, 9, 11) Sequence 2 (11, 11, 7, 9, 16, 4, 1) So sequence 1 would still be identical with sequence 2 as 11, 4, and 9 are duplicate elements

So I added a method public boolean equals(Sequence other) that checks whether the two sequences have the same values in the same order part 1, but what I need to do now is part 2 check whether two sequences have the same values in some order, ignoring duplicates.

import java.util.Arrays;
public class Sequence {
    private int[] values;
    public Sequence(int size)
    {
        values = new int[size];
    }
    public void set(int i, int n)
    { 
        values[i] = n; 
    }
    public boolean equals(Sequence obj) 
    {
        if (this == obj)
        {
            return true;
        }
        if (obj == null)
        {
            return false;
        }
        if (getClass() != obj.getClass())
        {
            return false;
        }
        Sequence other = (Sequence) obj;
        if (!Arrays.equals(values, other.values))
        {
            return false;
        }
        return true;
    }
    public static void main(String args[]){
        Sequence s = new Sequence(5);
        Sequence s2 = new Sequence(5);// new Sequence(4)
        s.set(0, 1);
        s2.set(0, 1);
        System.out.println(s.equals(s2));//will print true      
    }
}

I'm a little confused I know this is how you check duplicates but that is all I know I don't really know how use it in this scenario or how to ignore duplicates

for (int i = 0; i < values.length; i++) 
{ 
    for (int j = i + 1; j < other.length; j++) 
    { 
        if (values[i].equals(other[j]) ) {}
    }
}
William
  • 1
  • 2

5 Answers5

1

The slow approach is: walk the smaller array, and for each value, check if it is contained in the larger one. And then the other way round... So, without any further "smarts" you need to go for n * m comparisons. Times 2.

A more sophisticated solution: sort both arrays. Then start walking both arrays in turns (when both arrays are sorted, you don't need to iterate the second array repeatedly to figure if it contains a value from the other array). Then you only need to walk through both arrays once (but as said: in some alternating fashion).

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • You need to do it both ways. Check each value of array 1 exists in array 2 and vice versa. – DodgyCodeException Jun 06 '18 at 12:23
  • True. I updated the answer accordingly to make that more clear. – GhostCat Jun 06 '18 at 12:34
  • @GhostCat what would the comparison loop like trying do it this way only for (int k = 0; k < val1.length; k++) { for (int l = k + 1; l < val2.length; l++) { if (val1[k]=(val2[l])) {} } } I get an error saying int cannot be dereferenced – William Jun 06 '18 at 14:22
  • It seems that you are struggling with basic syntax problems already. I think you should focus on getting simpler examples to work for now. And please note: one question, one answer. Using comments to ask follow up questions isn't exactly good practice. – GhostCat Jun 06 '18 at 18:34
1

I think the easiest approach will be the following:

  • Sort the two arrays
  • Get the distinct values of the arrays.
  • Compare the sorted, unique arrays

Update, with thanks to @DodgyCodeException, it turns out it is more efficient to sort the array within the streams.

    int[] val1 = {1,1,4,9,16,9,7,4,9,11};
    int[] val2 = {11, 7, 9, 16, 7, 4, 1};

    //Compare should  be false
    System.out.println(Arrays.equals(val1, val2)); //false

    //Sort Array and get distinct Values
    //Assign to new int[] if you do not want to change the original arrays
    val1 = Arrays.stream(val1).sorted().distinct().toArray();
    val2 = Arrays.stream(val2).sorted().distinct().toArray();

    //Compare should be true
    System.out.println(Arrays.equals(val1, val2)); //true
  • I think the `distinct()` method here is not as efficient as it would have been if it knew that the arrays were sorted. Its implementation unnecessarily adds all the elements to an intermediate collection. – DodgyCodeException Jun 06 '18 at 12:37
  • @DodgyCodeException Do you mean it would be better to remove `Arrays.sort()` and alter the stream to `sorted().distinct()`? (I'm not that familiar with the efficiency of streams so I'm also still learning) –  Jun 06 '18 at 13:20
  • Yes. If you call `.distinct()` on an unsorted stream, it creates an intermediate `HashSet` to eliminate duplicates. It does that even if the stream is actually sorted but doesn't know that it is. However, if you call `.sorted()` _immediately before_ `.distinct()` then the `.distinct()` call knows that the stream is already sorted and so can just check the previous element to check uniqueness, and so it doesn't have to add the elements to a set. – DodgyCodeException Jun 06 '18 at 13:25
  • @DodgyCodeException Thank you for the explanation! I've updated my answer with the more efficient way. –  Jun 06 '18 at 13:31
  • 1
    Bonus: see https://stackoverflow.com/questions/34818533/how-to-compare-two-streams-in-java-8 how to compare two streams without creating temporary arrays – Mark Jeronimus Jun 06 '18 at 13:36
1

This is trivial with Java's Set mechanics. The following snippet will work as long as equals and hashCode are implemented correctly for type T:

private boolean equalWithDuplicates(T[] a, T[] b) {
    return new HashSet<>(Arrays.asList(a)).equals(new HashSet<>(Arrays.asList(b)));
}

However, as a commenter points out, this SO post seems to indicate arrays of primitives need to be boxed for the solution to work:

private boolean equalWithDuplicates(int[] a, int[] b) {
    Set<Integer> boxedA = Arrays.stream(a).boxed().collect(Collectors.toSet());
    Set<Integer> boxedB = Arrays.stream(b).boxed().collect(Collectors.toSet());
    return boxedA.equals(boxedB);
}
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35
Paul Benn
  • 1,911
  • 11
  • 26
  • This will not work. Arrays.asList produces unintuitive results for arrays of primitives. – DodgyCodeException Jun 06 '18 at 12:50
  • What are you referring to @DodgyCodeException? – Paul Benn Jun 06 '18 at 12:51
  • See https://stackoverflow.com/questions/1467913/arrays-aslist-not-working-as-it-should – DodgyCodeException Jun 06 '18 at 12:51
  • Oh, hold on, I've just noticed your `equalWithDuplicates` argument types are not primitive. In that case, how does the caller get from `int[]` to `T[]`? – DodgyCodeException Jun 06 '18 at 12:53
  • @Paul Benn I was looking at questions from a textbook as I have recently graduated I was just trying to refresh the language with me as I'm a little rusty. And in the textbook HashSets are like 5/6 chapters further ahead so I reckon I should probably know how to do it without hashsets just in case I got asked in an interview or something – William Jun 06 '18 at 12:55
  • @DodgyCodeException I made it generic on purpose to indicate this can eliminate duplicates from anything as long as the equals method on the object works as intended. I didn't know about the need for auto-boxing - I will edit my answer to reflect this. – Paul Benn Jun 06 '18 at 12:57
  • @William I would highly recommend you read about `HashSet` before going to any interviews. Not necessarily how they're implemented, but at least how they are used. – DodgyCodeException Jun 06 '18 at 13:00
  • @Paul Benn No I know a small bit about HashSet but it's just I'd be afraid an interviewer could throw a question like this at me and expect me to know how to do it without HashSet. Thanks for the advice though. I did quite a few interviews the questions are easy enough but the coding solutions seem very random so I want a great grasp on everything. – William Jun 06 '18 at 13:02
  • @William, most `Set` implementations use their own method to check if an element is present, if you want to read through their code. If you must do it without `Set` you can always just sort the array (O(n log n) in Java) and skip all duplicates you encounter during your comparison loop. – Paul Benn Jun 06 '18 at 13:06
  • @ Paul Benn Thanks – William Jun 06 '18 at 13:11
  • @Paul Benn What would the loop look like – William Jun 06 '18 at 14:19
0

Not sure what you mean, but if you want to remove duplicates, the easiest thing is to use a java.util.Set, like java.util.HashSet. Further, writing an equals(Sequence obj)-method could be considered bad practice, since it overloads the equals(Object obj).You probably want to overwrite that method, rahter then overload it.

Wanja Krah
  • 34
  • 3
0

I think your Sequence class could look like this one. The main idea for EQUALS_IGNORE_ORDER_AND_DUPLICATES is just transform input data to data, that could be use with equal function that you're already created.

final class Sequence {

    private final int[] values;

    public Sequence(int size) {
        values = new int[size];
    }

    public void set(int i, int n) {
        values[i] = n;
    }

    public static final BiPredicate<Sequence, Sequence> EQUALS = (seq1, seq2) -> Arrays.equals(seq1.values, seq2.values);

    public static final BiPredicate<Sequence, Sequence> EQUALS_IGNORE_ORDER_AND_DUPLICATES = (seq1, seq2) -> {
        Set<Integer> set1 = seq1 != null ? Arrays.stream(seq1.values).boxed().collect(Collectors.toSet()) : Collections.emptySet();
        Set<Integer> set2 = seq2 != null ? Arrays.stream(seq2.values).boxed().collect(Collectors.toSet()) : Collections.emptySet();
        return set1.equals(set2);
    };

}

Test:

int[] val1 = { 1, 1, 4, 9, 16, 9, 7, 4, 9, 11 };
int[] val2 = { 11, 7, 9, 16, 7, 4, 1 };

Sequence seq1 = new Sequence(val1.length);
Sequence seq2 = new Sequence(val2.length);

for (int i = 0; i < val1.length; i++)
    seq1.set(i, val1[i]);

for (int i = 0; i < val2.length; i++)
    seq2.set(i, val2[i]);

boolean res1 = Sequence.EQUALS.test(seq1, seq2);    // false
boolean res2 = Sequence.EQUALS_IGNORE_ORDER_AND_DUPLICATES.test(seq1, seq2);   // true
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35