Удаление дубликатов из массива Int [] - PullRequest
1 голос
/ 03 июля 2019

Я действительно боролся с этим в течение часа или около того.Я пытаюсь удалить все дубликаты из массива int [].Каждый элемент массива - это int [], содержащий позиции x & y тайла.Итак, это [[3, 1], [3, 12], ...].При создании своего мира я добавляю уже увиденные тайлы, поэтому я пишу функцию для «сжатия» массива тайлов.

Я попытался использовать hashSet & set, но по какой-то причине оба DS не удаляют дубликаты.Возможно ли проблема с переопределением сравнения (object1, object2) для int []?

// Принимает массив координат x, y (form: int [] {x, y}) и уплотняет егоудаляя дубликаты

private int[][] condenseTiles(int[][] tiles) {
    Set<int[]> setOfTiles = new LinkedHashSet<int[]>();

    for(int i = 0; i < tiles.length; i++){
        setOfTiles.add(tiles[i]);
    }

    System.out.println(setOfTiles.size());

    return tiles;
}

Я знаю, что существуют быстрые способы добавления каждого элемента в HashSet, но в настоящее время ничего не работает, и я все еще вижу дубликаты, поэтому я делаю это медленно и расширеннопуть.Для справки, прямо сейчас setOfTiles и тайлы имеют одинаковый размер независимо от того, что я делаю.Пожалуйста, дайте мне знать, если у вас есть какие-либо предложения.

1 Ответ

2 голосов
/ 03 июля 2019

Одно из возможных решений:

  • Создайте класс Tile, один с полями x и y int
  • Дайте классу приличные методы public boolean equals(Object o) и public int hashCode(), один, который относится кдве плитки с одинаковыми значениями x и y как равные и возвращающие один и тот же хэш-код
  • Поместите плитки в Set<Tile> с самого начала - это предотвратит повторяющиеся записи.

Например,

public class Tile {
    private int x;
    private int y;

    public Tile(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + x;
        result = prime * result + y;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Tile other = (Tile) obj;
        if (x != other.x)
            return false;
        if (y != other.y)
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Tile [" + x + ", " + y + "]";
    }

}

И протестировано с:

import java.util.LinkedHashSet;
import java.util.Set;

public class TestTile {
    public static void main(String[] args) {
        Set<Tile> tileSet = new LinkedHashSet<>();

        int[][] testData = {{1, 2}, {3, 4}, {5, 6}, {1, 2}, {5, 6}};
        for (int[] pair : testData) {
            Tile tile = new Tile(pair[0], pair[1]);
            tileSet.add(tile);
            System.out.println("Tile added: " + tile);
            System.out.println("All Tiles: ");
            for (Tile t : tileSet) {
                System.out.println("  " + t);
            }
            System.out.println();
        }

    }
}

Что возвращает:

Tile added: Tile [1, 2]
All Tiles: 
  Tile [1, 2]

Tile added: Tile [3, 4]
All Tiles: 
  Tile [1, 2]
  Tile [3, 4]

Tile added: Tile [5, 6]
All Tiles: 
  Tile [1, 2]
  Tile [3, 4]
  Tile [5, 6]

Tile added: Tile [1, 2]
All Tiles: 
  Tile [1, 2]
  Tile [3, 4]
  Tile [5, 6]

Tile added: Tile [5, 6]
All Tiles: 
  Tile [1, 2]
  Tile [3, 4]
  Tile [5, 6]

Другое возможное решение, если вы хотите использовать Java8 потоков, обратите внимание, что у него есть метод .filter(), но он работает только с hashCode и эквивалентными объектами для потоковой передачи, и если вы передаете потоковые массивы самостоятельно, это просто не будет работать.Обходной путь - использовать класс-оболочку, похожий на этот ответ переполнения стека на «Удалить дубликаты из списка объектов на основе свойства в Java 8» .

Класс-оболочка, который может работать:

import java.util.Arrays;

public class WrapperArray {
    int[] array;

    public WrapperArray(int[] array) {
        this.array = array;
    }

    @Override
    public int hashCode() {
        return Arrays.hashCode(array);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        WrapperArray other = (WrapperArray) obj;
        if (!Arrays.equals(array, other.array))
            return false;
        return true;
    }

    public int[] unwrap() {
        return array;
    }
}

И это можно проверить следующим образом:

import java.util.Arrays;

public class TestTile {
    public static void main(String[] args) {

        int[][] testData = { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 1, 2 }, { 5, 6 } };
        System.out.println("before filtering:");
        for (int[] is : testData) {
            System.out.println(Arrays.toString(is));
        }

        int[][] filteredArray = Arrays.stream(testData) // stream int[][] array
                .map(WrapperArray::new)     // map to our wrapper objects
                .distinct()                 // find distinct using wrapper equals/hashCode
                .map(WrapperArray::unwrap)  // convert back to int[]
                .toArray(int[][]::new);     // create new int[][] with results


        System.out.println("after filtering:");
        for (int[] is : filteredArray) {
            System.out.println(Arrays.toString(is));
        }
    }
}

Что возвращает:

before filtering:
[1, 2]
[3, 4]
[5, 6]
[1, 2]
[5, 6]
after filtering:
[1, 2]
[3, 4]
[5, 6]
...