C++ 从QList中删除重复对象

C++ 从QList中删除重复对象,c++,qt,list,qlist,C++,Qt,List,Qlist,我有一个QList,其中MyData有两个成员,int-id(唯一)和QString-name。我想删除基于名称的所有重复条目,并且该条目必须是具有相同名称的其他对象之间的最高id。有没有关于如何以最快的方式做这件事的建议?在这里,性能是一个非常重要的因素 我在谷歌搜索了一整天后的一些想法: qStableSort()它基于id(降序),然后循环通过QList,然后对于每个条目,当新的QList上不存在名称时,将条目复制到另一个新的QList 使用QList::toSet(删除所有重复条目),

我有一个
QList
,其中
MyData
有两个成员,
int-id
(唯一)和
QString-name
。我想删除基于
名称
的所有重复条目,并且该条目必须是具有相同
名称
的其他对象之间的最高
id
。有没有关于如何以最快的方式做这件事的建议?在这里,性能是一个非常重要的因素

我在谷歌搜索了一整天后的一些想法:

  • qStableSort()
    它基于id(降序),然后循环通过
    QList
    ,然后对于每个条目,当新的
    QList
    上不存在
    名称时,将条目复制到另一个新的
    QList
  • 使用
    QList::toSet
    (删除所有重复条目),并基于
    name
    提供运算符==()和qHash()实现,但唯一条目可能没有最高id
  • 使用
    std::list::unique
    ,但我不确定它是如何工作的
可以将具有以下属性的函数作为参数:

二元谓词,取两个类型相同的值 包含在列表中,返回true以删除作为传递的元素 容器中的第一个参数,否则为false。 这应该是一个函数指针或函数对象

因此,在您的情况下,您可以使用以下函数:

bool shouldRemove(MyData first, MyData second)
{
    // remove only if they have the same name and the first id
    // is smaller than the second one 
    return ( first.name == second.name && 
             first.id <= second.id ); 
}
这个怎么样:

QList<MyData> theList = ...;

QHash<QString, int> nameToIdMap;

for (const MyData& element : theList) {

    auto iter = nameToIdMap.find(element.name);
    if (iter != nameToIdMap.end() && iter.second > element.id) {
        // If item exists in map (name already occured) and the ID is 
        // bigger than in the current element, just skip the current element.
        continue;
    }

    // Otherwise, insert/overwrite it in the map.
    nameToIdMap[element.name] = element.id;
});

// nameToIdMap should now map unique names to highest IDs. If desired,
// you could copy it back into a new list by iterating over the map's entries
// and creating new MyData elements accordingly.
QList theList=。。。;
QHash nameToIdMap;
for(常量MyData&元素:列表){
auto iter=nameToIdMap.find(element.name);
if(iter!=nameToIdMap.end()&&iter.second>element.id){
//如果映射中存在项(名称已出现),且ID为
//大于当前元素,只需跳过当前元素。
继续;
}
//否则,请在地图中插入/覆盖它。
nameToIdMap[element.name]=element.id;
});
//nameToIdMap现在应该将唯一名称映射到最高ID。如果需要,
//您可以通过迭代映射的条目将其复制回新列表
//并相应地创建新的MyData元素。
在我看来,这样做的好处是:您不必将列表转换为
std
-容器并返回,如果您找到一种方法继续使用
QMap
而不是
QList
,您只需在初始列表上迭代一次。而
QHash
将为您提供摊销
O(1)
查找复杂性


编辑:更改为
QHash

我是通过STL容器完成的,但我认为将其转换为Qt容器并不困难

包括
#包括
#包括
#包括

使用标准的C++库函数(5个< /P>:要么<代码> STD::清单:独特的或“一般<代码> STD::独特的< /代码>函数”)意味着你必须将数据复制到一个标准容器,然后将它们复制回QList。你已经使用lambdas——为什么不进行排序和设置比较?@致命吉他,我不喜欢长的lambdas,这就是为什么我没有在sort中使用它。另一方面,我不知道如何在集合定义中使用lambda。在我的示例中,你能告诉我如何通过lambda声明集合吗?谢谢,显然在集合定义中是不可能的。。太糟糕了,我什么都喜欢使用lambdas。这也是一个好主意,但我在问题中漏掉了一个要点:我在
MyData
中实际上有两个以上的成员。我的缺点:(这不是什么大问题:只需使用
QHash
,然后将
if
-语句的第二个条件更改为:
iter.second.id>element.id
。或者将
MyData*
放入QHash,以避免复制所有MyData.+1:语法很酷!我必须尽快切换到新标准:-)
// lessThan is a function that sorts first by name and then by id
qSort(qList.begin(), qList.end(), lessThan );
QList<MyData>::iterator it = std::unique (qList.begin(), qList.end(), shouldRemove);
qList.erase(it, qList.end());
QList<MyData> theList = ...;

QHash<QString, int> nameToIdMap;

for (const MyData& element : theList) {

    auto iter = nameToIdMap.find(element.name);
    if (iter != nameToIdMap.end() && iter.second > element.id) {
        // If item exists in map (name already occured) and the ID is 
        // bigger than in the current element, just skip the current element.
        continue;
    }

    // Otherwise, insert/overwrite it in the map.
    nameToIdMap[element.name] = element.id;
});

// nameToIdMap should now map unique names to highest IDs. If desired,
// you could copy it back into a new list by iterating over the map's entries
// and creating new MyData elements accordingly.
#include <list>
#include <set>
#include <iostream>
#include <algorithm>

struct MyData {
    int id;
    std::string name;
};

struct MyDataSortComparator {
    bool operator()( const MyData & left, const MyData & right ) {
        if ( left.name < right.name ) {
            return true;
        }
        else if ( left.name > right.name ) {
            return false;
        }
        return left.id > right.id;
    }
};

struct MyDataSetComparator {
    bool operator()( const MyData & left, const MyData & right ) {
        return left.name < right.name;
    }
};


int main() {
    std::list< MyData > theList = {
        { 1, "Dickson" },
        { 2, "Dickson" },
        { 3, "Dickson" },
        { 2, "borisbn" },
        { 1, "borisbn" }
    };
    std::set< MyData, MyDataSetComparator > theSet;
    theList.sort( MyDataSortComparator() );
    std::for_each( theList.begin(), theList.end(), []( const MyData & data ) {
        std::cout << data.id << ", " << data.name << std::endl;
    } );
    std::for_each( theList.begin(), theList.end(), [&theSet]( const MyData & data ) {
        theSet.insert( data );
    } );
    std::cout << "-------------------" << std::endl;
    std::for_each( theSet.begin(), theSet.end(), []( const MyData & data ) {
        std::cout << data.id << ", " << data.name << std::endl;
    } );
}