Лучший способ удалить дубликаты из многомерного массива?

Допустим, у меня есть массив:

double[][] points = {{0.0, 0.0}, {1.0, 1.0}, {1.0, 1.0},  {2.0, 2.0}};

Я хочу создать новый массив без повторяющейся записи {1.0, 1.0} - как лучше всего это сделать?

Дополнительная информация:

  • Массив отсортирован, но только по первому компоненту, поэтому можно иметь

    {1.0, 2.0}, {1.0, 1.0}, {1.0, 2.0}
    

    Вот как я получаю данные, я не могу изменить первоначальный механизм сортировки.

  • Текущим ограничением являются два измерения, но массив может содержать тысячи точек.


person htorque    schedule 06.07.2011    source источник
comment
Итак... глупый ответ double[][] points2 = {{0.0, 0.0}, {1.0, 1.0}, {2.0, 2.0}}; Я уверен, что это не то, что вам нужно! Вы хотите отфильтровать все дубликаты? Если да, то гарантируете ли вы, что массив отсортирован? ... Просьба уточнить.   -  person Ed Staub    schedule 06.07.2011
comment
Пробовали ли вы грубую силу?   -  person Kal    schedule 06.07.2011
comment
Вам нужно беспокоиться о 2 измерении или оно может подняться до N измерения?   -  person Alvin    schedule 06.07.2011
comment
В каких условиях вы работаете? Если у вас достаточно маленький массив, вы можете просто выполнить двойной цикл и сравнить каждую пару элементов.   -  person dckrooney    schedule 06.07.2011
comment
@EdStaub: да, я этого и хочу. Сделайте a b b c a b c.   -  person htorque    schedule 06.07.2011


Ответы (5)


Самый простой ответ: сравните элементы массива попарно и удалите дубликаты. Это не будет хорошо масштабироваться, но может и не понадобиться.

Более сложно: посмотрите на что-то вроде сортировки по основанию. После того, как вы отсортировали первый, а затем второй элемент подмассива, вы можете пройтись по всему массиву и удалить дубликаты. Это улучшит масштабирование, но может быть излишним (в зависимости от вашей ситуации).

Лучше всего (вероятно): создать набор элементов массива. Пройтись по массиву; для каждого элемента проверьте, не находится ли он уже в наборе. Если это так, удалите его из массива. Если нет, добавьте его в набор и продолжайте. Это, вероятно, лучший подход, если только дублирование массива не является проблемой пространства.

person dckrooney    schedule 06.07.2011
comment
Я тоже думал о подходе Set, но я не понимаю, как это реализовать, поскольку Set позволяет мне с радостью добавить new double[] {1.0, 1.0} дважды. - person htorque; 06.07.2011
comment
@htorque: метод add в реализации набора Java возвращает true, если объект был добавлен успешно (т. е. не был дубликатом), и false в противном случае. - person dckrooney; 06.07.2011
comment
Я знаю, но он оба раза возвращает true два. - person htorque; 07.07.2011
comment
кроме того, на самом деле он будет сохранять только один экземпляр данных, поэтому вам даже не нужно проверять результаты метода add. Вы могли бы потенциально добавить все в набор, а затем запросить массив из набора. - person Clockwork-Muse; 07.07.2011
comment
@htorque- я предполагаю, что это из-за того, как вы добавляете элементы в набор ... У меня нет под рукой компилятора Java, но я предполагаю, что Set add () сравнивает объект, который вы добавляете к набору (двойной [] {...}) к другим элементам в наборе. Однако я не думаю, что у примитивных массивов есть метод equals(), поэтому на самом деле сравниваются только ссылки на элементы, а не значения элементов. - person dckrooney; 07.07.2011
comment
Да, тип double[] не переопределяет equals(), поэтому вы сравниваете ссылки. Вам нужно будет использовать собственный компаратор или какое-либо другое средство сравнения элементов. - person Jesse Webb; 07.07.2011

Вам не нужно создавать набор из всех точек — только из значений Y для каждого X, потому что они отсортированы по X. Использование HashSet требует автоупаковки каждого значения — в вопросах эффективности используйте TDoubleHashSet. Это, вероятно, где-то близко к оптимальному - частично в зависимости от частоты дубликатов.

Порядок такой же, как и на входе, но когда для заданного значения X имеется несколько значений Y, они могут быть выведены в другом порядке, чем на входе.

double prevPoint[];
// If efficiency matters, use Trove TDoubleHashSet instead.
HashSet<Double> set;
ArrayList<double[]> buffer;

double[][] filter(double[][] points)
{
    prevPoint = new double[]{Double.NaN, Double.NaN};
    set = new HashSet<Double>();
    // Allocate space as if there were no duplicates.
    // Tweak if expecting lots of dupes.
    buffer = new ArrayList<double[]>(points.length);
    for ( double[] point : points )
    {
        if ( prevPoint[0] != point[0] )
        {
            emitSet();
            set.clear();

        }
        set.add(point[1]);
        prevPoint = point;
    }

    // output hashset
    emitSet();

    return buffer.toArray(new double[buffer.size()][2]);
}

private void emitSet()
{
    for ( double y : set )
    {
        // optimize out array create for common case of only 1 y with the same x.
        // get rid of this complexity if efficiency not needed.
        if ( y == prevPoint[1] )
        {
            buffer.add(prevPoint);
        }
        else
        {
            buffer.add(new double[] {prevPoint[0], y});
        }
    }
}
person Ed Staub    schedule 06.07.2011

создать набор элементов «массива». Элемент «массив» должен возвращать равное значение true, если содержит информацию о равных элементах.

person Fedor Skrynnikov    schedule 06.07.2011


Одна простая вещь, которую вы можете сделать, это проверить, прежде чем добавлять новый элемент в ваш массив.

person John Kane    schedule 06.07.2011
comment
Не вариант. Мне нужно, чтобы дубликаты оставались в оригинале, без них может работать только одна единственная функция — с гораздо меньшей болью. ;) - person htorque; 06.07.2011
comment
это очень плохо. нет никакого реального эффективного способа удалить их. Вам нужно будет отсортировать массив или перебрать массив из N элементов, N раз для каждого элемента. - person John Kane; 06.07.2011
comment
Разве вы не можете создать оба массива одновременно с заполнением одного дубликатами? Тот, который вам нужен без дубликатов, может быть сохранен в наборе, и вам не придется беспокоиться о проверке дубликатов. - person Jesse Webb; 07.07.2011