Unable to use Set to remove duplicate pair numbers

2019-09-18 09:52发布

问题:

Let's say I want to generate 20 random numbers on a 8 by 6 grid.(8 columns, 6 rows) . Based on the answer from here:Creating random numbers with no duplicates, I wrote my code like this:

Random randomNumGenerator = new Random();
Set<Integer[][]> generated = new LinkedHashSet<Integer[][]>();
while (generated.size() < 20) {
    int randomRows = randomNumGenerator.nextInt(6);
    int randomColumns = randomNumGenerator.nextInt(8);
    generated.add(new Integer[][]{{randomRows,randomColumns}});
}

In reality what happens is the Set see Integer[][]{{5,5}}; and Integer[][]{{5,5}};as NOT duplicate.Why? Even tho my purpose is to get 20 non-duplicate pair of numbers, this does not work. How do I fix this?

回答1:

The Set checks for duplicates using the equals method (and also the hashCode method) of its inner type, but the Integer[][]'s equals method compares the memory addresses and not the contents.

Why do you use a Set of Integer[][] if you just want to store pairs? Unfortunately, in Java there is no Pair class, but if you do not want to create your own, you can use the Map.Entry for that.

Random randomNumGenerator = new Random();
Set<Map.Entry<Integer, Integer>> generated = new LinkedHashSet<>();
while (generated.size() < 20) {
    int randomRows = randomNumGenerator.nextInt(6);
    int randomColumns = randomNumGenerator.nextInt(8);
    generated.add(new AbstractMap.SimpleEntry<>(randomRows,randomColumns));
}
System.out.println(generated);


回答2:

Array equals is == in Java, so an array is only equal to itself. Normaly you use Arrays.equals(array1, array2) to compare them by content, but in this case, arrays are simply the wrong choice. You can either create a bean, as rafalopez79 suggested of use an array of Collections (List in your case), as a List will compare the content on equals, see the documentation. Choice is pretty much yours, a bean would probably be a bit cleaner.



回答3:

How about this code. I ran it through the debugger, it works nicely and yes, the contains() method checks the value of the Integer, not the reference. You can change the range of the random number as needed, I used 5 to facilitate testing. Yes I know it's not very robust, as written this will be an endless loop (because of the limited range of 5) but it's a simple example to make the point.

UPDATE: Actually this has a bug in that it won't check for uniqueness across all the rows, but that's easily fixed as well. I just re-read the original question and looking at the original code I'm not sure I know what you want exactly. If you just want a grid with 48 unique Intergers arranged 8 by 6 this will do it, but there are several ways to do this.

    final int rows = 6;
    final int cols = 8;

    Random randomGenerator = new Random();


    ArrayList[] grid = new ArrayList[rows];

    for(int i=0; i<rows; i++)
    {
        grid[i] = new ArrayList<Integer>();

        for(int j=0; j<cols; j++)
        {
            for(;;)
            {
                Integer newInt = new Integer(randomGenerator.nextInt(5));               
                if(!grid[i].contains(newInt))
                {
                    grid[i].add(newInt);
                    break;
                }   
            }

        }
    }


标签: java set