Java: how to be sure to store unique arrays based on its values ​​in a list

I have a series of one-dimensional arrays Object [] (these objects are primitive types if that helps)

I want to store these arrays in a list, but only arrays whose contents are unique from the rest.

My first aproximation was to iterate over the array stored in Set. Set the array value to Arrays.hashCode (array) and store the array in the desired list if the value was not contiguous in the set.

But later I realize that two arrays with different contents can produce the same hashcode (not often hopefully)

can anyone help?

Can a very frequent hashcode clash (same code from different content) be expected?

+2


source to share


6 answers


It sounds like you need a LinkedHashSet (preserving insertion order while preserving uniqueness) and then wrap your arrays in an object that implements hashcode and is equal, which makes sense for your arrays. The first approximation might just be the Arrays.asList () method, but you are claiming in your question that you are using primitives in the Object [] array. Either you are relying on autoboxing, or you are not actually using the Object [] array, but rather int [], long [], float [] as needed. Arrays.asList () will not work correctly with these types.

Edit: As requested for comment, here's the code for the wrapper class:



  public class ArrayWrapper { 
       private Object[]array; 
       public ArrayWrapper(Object[] array) { this.array = array; } 
       public Object[] getArray() { 
                 Object[] newArray=new Object[array.length]; 
                 System.arraycopy(array,0,newArray,0,array.length); 
                  return newArray; 
       } 
       public int hashCode() { return Arrays.hashCode(array); } 
       public boolean equals(Object obj) { 
              boolean b=false;
              if(obj instanceof ArrayWrapper){ 
                     b=Arrays.equals(this.array,((ArrayWrapper)obj).getArray()); 
              } 
              return b; 
       } 
 }

      

+2


source


The problem is that you will have arrayX and arrayY with both content [a, b, c] and a set, not counting them as equal? Will [a, b, c] and [c, a, b] be considered equal or not?



I would say define a comparator that determines "equality" for the arrays exactly as you like, and then insert each array into a set that uses the custom comparator you created.

+2


source


If the hashcode is the same, then you just check its details in detail.

+1


source


It is assumed that you assume that the arrays {1,2,3} and {3,2,1} are not duplicated.

Don't store hashcode of arrays in Set, keep whole lists for Set.

Convert your arrays to List s. Lists have consistent equals and hashCode methods. Two lists are defined equal if they contain the same elements in the same order, and the hash of the List will match the equals method.

  List<Object> list = Arrays.asList(array);

      

Here's the whole algorithm. (Unused code, but should work).

Set<List<Object>> findUniqueLists(List<List<Object>> allLists) {
   Set<List<Object>> uniqueSet = new LinkedHashSet<List<Object>>();
   uniqueSet.addAll(allLists);

   Set<List<Object>> processedSet = new LinkedHashSet<List<Object>>();

   for(List<Object> list : allLists) {
       if(processedSet.contains(list)) {
           // duplicate found!
           uniqueSet.remove(list);
       } else {
           // no duplicate
           processedSet.add(list)
       }
    }
    return uniqueSet;
}

      

+1


source


Try something like this:

EDIT

Below is the working and working code:

bash-3.2$ cat ArraysTest.java 
import java.util.*;
public class ArraysTest {
    public static void main( String [] args ) {
        Set<Integer[]> set = new TreeSet<Integer[]>( new Comparator<Integer[]>() {
            public int compare( Integer[] one, Integer[] two ) {
                if( Arrays.equals( one, two ) )  {
                    return 0;
                }
                return Arrays.hashCode( one ) - Arrays.hashCode( two );
            }
            public boolean equals( Object o ){ return false; }
        });

        set.add( new Integer[]{1,2,3});
        set.add( new Integer[]{1,2,3});
        set.add( new Integer[]{3,2,1});

        for( Integer[] i : set ) {
            System.out.println( Arrays.asList( i ) );
        }

    }
}

bash-3.2$ javac ArraysTest.java  
bash-3.2$ java ArraysTest
[1, 2, 3]
[3, 2, 1]
bash-3.2$ 

      

You will need to do a bit of work for this to work, this is just a sample and not the actual current code.

As you know, Set takes only one element, and creation TreeSet

with a custom comparator allows you to tell the set what is equal to you.

Methods

Arrays.equals()

describe:

.. two arrays are equal if they contain the same elements in the same order ...

+1


source


For effective comparison, a two-step approach is sometimes used:

  • hashCode

    discards many potential matches
  • if two hashCodes are equal, the objects themselves are tested for equality (depends on their method equals

    )

About your Object[]

primitive type, please remember the following:
To add a primitive type to Object[]

, it will always be boxed / unpacked .
So you don't actually have primitive types like the contents of your arrays.

To keep primitive types, the arrays themselves must have primitive types such as int[]

.

0


source







All Articles