2

У меня есть список объектов Tweet (доморощенный класс), и я хочу, чтобы удалить ОКОЛО дубликатов на основе их текст, используя расстояние Левенштейн. Я уже удалял идентичные дубликаты, хешируя тексты твитов, но теперь хочу удалить тексты, которые идентичны, но имеют до 2-3 разных символов. Поскольку это подход O (n^2), я должен проверить каждый текст твита со всеми доступными другими. Вот мой код до сих пор:ява - Удалить почти дубликаты из списка

int distance; 
for(Tweet tweet : this.tweets) { 
    distance = 0; 
    Iterator<Tweet> iter = this.tweets.iterator(); 
    while(iter.hasNext()) { 
     Tweet currentTweet = iter.next(); 
     distance = Levenshtein.distance(tweet.getText(), currentTweet.getText()); 
     if(distance < 3 && (tweet.getID() != currentTweet.getID())) { 
      iter.remove(); 
     } 
    } 
} 

Первая проблема заключается в том, что код бросает ConcurrentModificationException в какой-то момент и никогда не завершается. Второй: могу ли я сделать что-нибудь лучше, чем этот двойной цикл? Список твитов содержит около 400 000 твитов, поэтому мы говорим о 160 миллиардах итераций!

+2

«Вы уже удалили одинаковые дубликаты путем хэширования текстов твитов». Что теперь? 'a.hashCode() == b.hashCode()' ** не подразумевает ** 'a.equals (b) == true'! Верно только противоположное значение. И это должно быть верно для ** любого хеширования, поскольку переменное пространство для хэша должно быть меньше, чем пространство переменных исходного значения (или вы можете просто использовать _it_ как хэш). –

+6

Вы удаляете объекты из списка, который вы зацикливаете во внешнем для каждого. Это не разрешено. – Manu

+0

@BoristheSpider Я не использовал функцию hashCode() для объектов твита, но для текстов. Таким образом, твиты разных людей, которые имеют идентичные тексты твитов, были удалены. На самом деле, из 1M твитов изначально, теперь у меня 390K. – Lefteris008

ответ

-1

Что касается ConcurrentModificationException: Как другие отметили, я удаление элементов из списка, который я также перебор во внешнем для-каждого. Изменение для каждого в нормальное для решения проблемы.

Что касается O(n^2) подхода: Там нет «лучше» алгоритма относительно его сложности, чем O(n^2) подхода. То, что я пытаюсь сделать, - это сравнение «все-ко всем», чтобы найти почти повторяющиеся элементы. Конечно, есть оптимизация для уменьшения общей емкости n, параллелизация параллельного анализа подписок исходного списка, но сложность всегда квадратична.

+0

«Замена для каждого в обычном режиме для решения проблемы». Это ничего не решает, это просто проблема. Причина, по которой список выдает «ConcurrentModificationException», заключается в том, что удаление элементов во время итерации ** должно выполняться с помощью «Итератора», иначе вы рискуете бежать в конце «списка» в лучшем случае. В худшем случае вы молча пропускаете элемент во время итерации. Pro tip: учитывайте ошибки, не маскируйте их. –

-1

Это решение работает для вопроса в руке (до сих пор проходят с возможными входами), но нормальный набор операций для удаления дубликатов не будет работать, если вы не осуществить полный контракт для сравнения, чтобы вернуть 1,0 и -1 ,


Почему вы не выполняете свою собственную операцию сравнения с помощью Set, который может иметь только разные значения. Это будет O (n log (n)).

Set set = new TreeSet(new Comparator() { 
      @Override 
      public int compare(Tweet first, Tweet second) { 
       int distance = Levenshtein.distance(first.getText(), second.getText()); 
       if(distance < 3){ 
        return 0; 
       } 
       return 1; 
      } 
     }); 
     set.addAll(this.tweets); 
     this.tweets = new ArrayList<Tweet>(set); 
+1

«Это будет O (n^2), как ваш код_». Неправильно. 'add' на' TreeSet' является 'O (lg n)', делая это 'n' times будет 'O (n lg n)' - ** much ** less 'O (n^2)' .. . Но ваш метод compareTo не работает так, как если бы 'a.compareTo (b)> c', то' b.compareTo (a) '** должен быть **' -c'. См. [Документация] (https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html#compare-T-T-). Это означает, что поведение «TreeSet» ** не определено ** с помощью компаратора. –

+0

Да, это O (n log (n)). Я обновлю ответ. Но compareTo будет отлично работать для проблемы. –

+0

@AshraffAliWahab Нет. Это не так. Потому что вы полагаетесь на свойство 'TreeSet' - чтобы не было разрешено два элемента, для которых' a.compareTo (b) == 0'. Это свойство не может быть гарантировано, если вы не выполняете контракт «compareTo» - вы не определяете общий порядок. Таким образом, этот ответ ошибочен и поощряет ужасную практику вызова неопределенного поведения и предполагает, что это нормально, потому что не существует исключения. –

Смежные вопросы