Use a better data structure to track uniques songs when removing duplicate.

This commit is contained in:
Arnaud Bienner 2012-11-22 02:06:29 +01:00
parent cf22a91c6a
commit af8e8c753e
3 changed files with 41 additions and 25 deletions

View File

@ -1114,12 +1114,6 @@ bool Song::IsMetadataEqual(const Song& other) const {
d->cue_path_ == other.d->cue_path_;
}
bool Song::IsDuplicate(const Song& other) const {
return url() == other.url() ||
(title().toLower() == other.title().toLower() &&
artist().toLower() == other.artist().toLower());
}
bool Song::IsEditable() const {
return d->valid_ && !d->url_.isEmpty() && !is_stream() &&
d->filetype_ != Type_Unknown && !has_cue();
@ -1136,6 +1130,16 @@ uint qHash(const Song& song) {
return qHash(song.url().toString()) ^ qHash(song.beginning_nanosec());
}
bool Song::IsSimilar(const Song& other) const {
return title().compare(other.title(), Qt::CaseInsensitive) == 0 &&
artist().compare(other.artist(), Qt::CaseInsensitive) == 0;
}
uint HashSimilar(const Song& song) {
// Should compare the same fields as function IsSimilar
return qHash(song.title().toLower()) ^ qHash(song.artist().toLower());
}
bool Song::IsOnSameAlbum(const Song& other) const {
if (is_compilation() != other.is_compilation())
return false;

View File

@ -262,7 +262,7 @@ class Song {
// Comparison functions
bool IsMetadataEqual(const Song& other) const;
bool IsOnSameAlbum(const Song& other) const;
bool IsDuplicate(const Song& other) const;
bool IsSimilar(const Song& other) const;
bool operator==(const Song& other) const;
@ -283,5 +283,7 @@ typedef QList<Song> SongList;
Q_DECLARE_METATYPE(QList<Song>);
uint qHash(const Song& song);
// Hash function using field checked in IsSimilar function
uint HashSimilar(const Song& song);
#endif // SONG_H

View File

@ -62,6 +62,7 @@
#include <QtDebug>
#include <algorithm>
#include <unordered_map>
#include <boost/bind.hpp>
using smart_playlists::Generator;
@ -1919,36 +1920,45 @@ void Playlist::RemoveDeletedSongs() {
removeRows(rows_to_remove);
}
struct SongSimilarHash {
long operator() (const Song& song) const {
return HashSimilar(song);
}
};
struct SongSimilarEqual {
long operator() (const Song& song1, const Song& song2) const {
return song1.IsSimilar(song2);
}
};
void Playlist::RemoveDuplicateSongs() {
QList<int> rows_to_remove;
QHash<Song, int> unique_songs;
std::unordered_map<Song, int, SongSimilarHash, SongSimilarEqual> unique_songs;
for (int row = 0; row < items_.count(); ++row) {
PlaylistItemPtr item = items_[row];
Song song = item->Metadata();
const Song& song = item->Metadata();
bool found_duplicate = false;
QHashIterator<Song, int> iterator(unique_songs);
while (iterator.hasNext() && !found_duplicate) {
iterator.next();
Song uniq_song = iterator.key();
auto uniq_song_it = unique_songs.find(song);
if (uniq_song_it != unique_songs.end()) {
const Song& uniq_song = uniq_song_it->first;
if (song.IsDuplicate(uniq_song)) {
if (song.bitrate() > uniq_song.bitrate()) {
rows_to_remove.append(unique_songs[uniq_song]);
unique_songs.remove(uniq_song);
unique_songs.insert(song, row);
}
else {
rows_to_remove.append(row);
}
found_duplicate = true;
if (song.bitrate() > uniq_song.bitrate()) {
rows_to_remove.append(unique_songs[uniq_song]);
unique_songs.erase(uniq_song);
unique_songs.insert(std::make_pair(song, row));
} else {
rows_to_remove.append(row);
}
found_duplicate = true;
}
if (!found_duplicate)
unique_songs.insert(song, row);
if (!found_duplicate) {
unique_songs.insert(std::make_pair(song, row));
}
}
removeRows(rows_to_remove);