C++ 根据其他列表排序列表

C++ 根据其他列表排序列表,c++,stl,C++,Stl,鉴于: 我在文档中搜索了一些方法,但我只找到了一些方法来对元素进行排序,并在元素之间进行比较。假设数据是由外部处理的,而您没有容器的选择: INPUT objectList = {o1, o2, o3}; idList = {2, 3, 1}; ACTION sort(objectList, idList); OUTPUT objectList = {o2, o3, o1}; 但这个解决方案不是最优的,我相信有人会提出更好的解决方案 编辑:成对的默认比较运算

鉴于:


我在文档中搜索了一些方法,但我只找到了一些方法来对元素进行排序,并在元素之间进行比较。

假设数据是由外部处理的,而您没有容器的选择:

INPUT
    objectList = {o1, o2, o3};
    idList = {2, 3, 1};

ACTION
    sort(objectList, idList);

OUTPUT
    objectList = {o2, o3, o1};
但这个解决方案不是最优的,我相信有人会提出更好的解决方案

编辑:成对的默认比较运算符要求为第一个和第二个成员定义它。因此,最简单的方法是提供lambda


Edit2:出于某种原因,如果对包装器使用
std::list
,则不会生成此代码。但是,如果使用
std::vector
(),也可以。

您可以将对象存储在
std::map
中,并将
id
作为键。然后遍历
idList
,将对象及其
id
map
中取出

{
   auto objectList_it = std::begin( objectList );
   for( const auto& e: wrapper )
      *objectList_it++ = e;
}
std::map objectMap;
对于(自动itr=objectList.begin();itr!=objectList.end();itr++)
{
insert(std::make_pair(itr->id,*itr));
}
std::list newObjectList;
对于(自动itr=idList.begin();itr!=idList.end();itr++)
{
//如果您的idList包含的ID未出现在objectList中,则此处可能会失败
newObjectList.push_back(objectMap[*itr]);
}
//现在newObjectList在idList中按顺序排序

std::list
有一个
sort
成员函数,可以与自定义比较函子一起使用

该自定义函子必须在
idList
中查找对象的
id
,然后可以使用
std::distance
计算元素在
idList
中的位置。它对要比较的两个对象都执行此操作,如果第一个位置小于第二个位置,则返回true

以下是一个例子:

std::map<int, Object> objectMap;
for (auto itr = objectList.begin(); itr != objectList.end(); itr++)
{
    objectMap.insert(std::make_pair(itr->id, *itr));
}

std::list<Object> newObjectList;
for (auto itr = idList.begin(); itr != idList.end(); itr++)
{
    // here may fail if your idList contains ids which does not appear in objectList
    newObjectList.push_back(objectMap[*itr]);
}

// now newObjectList is sorted as order in idList
#包括
#包括
#包括
#包括
结构对象
{
int-id;
};
int main()
{
对象o1={1};
对象o2={2};
对象o3={3};
std::list objectList={o1,o2,o3};
std::list const idList={2,3,1};
objectList.sort([&](Object const&first,Object const&second)
{
auto const id\u find\u iter1=std::find(begin(idList)、end(idList)、first.id);
auto const id\u find\u iter2=std::find(begin(idList)、end(idList)、second.id);
if(id_find_iter1==end(idList)|id_find_iter2==end(idList))
{
抛出std::runtime_错误(“找不到ID”);
}
auto const pos1=std::distance(开始(idList),id\u find\u iter1);
auto const pos2=std::distance(开始(idList),id\u find\u iter2);
返回pos1std::cout这里是另一个变体,它在
O(n logn)
中工作。这是渐近最优的

#include <iostream>
#include <list>
#include <algorithm>
#include <stdexcept>

struct Object
{
    int id;
};

int main()
{
    Object o1 = { 1 };
    Object o2 = { 2 };
    Object o3 = { 3 };
    std::list<Object> objectList = { o1, o2, o3 };
    std::list<int> const idList = { 2, 3, 1 };

    objectList.sort([&](Object const& first, Object const& second)
    {
        auto const id_find_iter1 = std::find(begin(idList), end(idList), first.id);
        auto const id_find_iter2 = std::find(begin(idList), end(idList), second.id);
        if (id_find_iter1 == end(idList) || id_find_iter2 == end(idList))
        {
            throw std::runtime_error("ID not found");
        }
        auto const pos1 = std::distance(begin(idList), id_find_iter1);
        auto const pos2 = std::distance(begin(idList), id_find_iter2);
        return pos1 < pos2;
    });

    for (auto const& object : objectList)
    {
        std::cout << object.id << '\n';
    }
}
注意:这个测试显示了最坏的情况,因为在我的例子中,只有索引列表被随机排序,而对象列表(按顺序插入到地图中)被随机排序已排序。因此重新平衡显示了其所有效果。如果对象列表是随机的,则性能将表现得更相似,即使性能总是更差。当对象列表完全随机时,向量列表的性能甚至会更好


因此,对于1000个条目,差异已经相当大。因此,我强烈支持基于向量的方法。

我会发现,在这种情况下,我会使用指针而不是ID,这很奇怪。不过,这可能有一些使用案例

请注意,在下面的所有示例中,我假设ids列表中包含的所有id都是一个

自己写 您要解决的问题是根据另一个列表中ID的顺序创建/排序对象列表

做这件事的天真方式就是自己写:

N         map         vector
1000      90          75
10000     1400        940
100000    24500       15000
1000000   660000      250000   
void sortByIdVector(std::list&list,const std::list&id)
{
自动旧列表=标准::移动(列表);
list=std::list{};
用于(自动id:ids)
{
auto iteelement=std::find_if(oldList.begin(),oldList.end(),[id](const Object&obj){return id==obj.id;});
列表。向后放置(标准::移动(*itElement));
oldList.erase(iteelement);
}
}
如果您使用排序向量作为输入,您可以优化此代码以获得最佳性能。我将让您来完成这项工作

使用排序 对于这个实现,我假设这是std::vector而不是std::list,因为这是请求元素索引的更好的容器

size\u t getIntendedIndex(常量std::vector&id、常量Object&obj)
{
auto iteelement=std::find_if(ids.begin(),ids.end(),[obj](int-id){return-id==obj.id;});
返回iteElement-id.begin();
}
void sortByIdVector(标准::列表和列表,常量标准::向量和ID)
{
list.sort([&id](const-Object&lhs,const-Object&rhs){返回getIntendedIndex(ids,lhs)
插入 另一种更适合std::vector的方法是简单地在正确的位置插入元素,并且比std::sort更有效

size_t getIntendedIndex(const std::vector<int> &ids, const Object &obj)
{
    auto itElement = std::find_if(ids.begin(), ids.end(), [obj](int id) { return id == obj.id; });
    return itElement - ids.begin();
}

void sortByIdVector(std::list<Object> &list, const std::vector<int> &ids)
{
     list.sort([&ids](const Object &lhs, const Object &rhs){ return getIntendedIndex(ids, lhs) < getIntendedIndex(ids, rhs); });
}
void sortByIdVector(std::vector&list,const std::vector&id)
{
自动旧列表=标准::移动(列表);
list=std::vector{};
list.resize(oldList.size());
用于(对象和对象:旧列表)
{
auto&newLocation=list[getIntendedIndex(ids,obj)];
newLocation=std::move(obj);
}
}
我们的想法是检查我们是否在
idList
中的
o2.id
之前找到
o1.id
。 我们搜索
o1.id
,增加找到的位置,然后搜索
o2.id
:如果找到,则意味着o1 测试

objectList.sort([&idList] (const Object& o1, const Object& o2) -> bool
   { return std::find(++std::find(idList.begin(), idList.end(), o1.id),
       idList.end(), o2.id)
       != idList.end();
   });
#包括
#包括
#包括
#包括
结构对象{
int-id;
字符串名;
};
int main()
{
列表对象列表{{1,“1{1},{2”,“2{1},{3”,“3{1},{2”,“2},{1”,“1{2},{4”,“4{1},{3”,“3{2},{4”,“4};
列出空闲列表{3,2,4,1};
objectList.sort([&idList](常量对象)
N         map         vector
1000      90          75
10000     1400        940
100000    24500       15000
1000000   660000      250000   
void sortByIdVector(std::list<Object> &list, const std::list<int> &ids)
{
    auto oldList = std::move(list);
    list = std::list<Object>{};
    for (auto id : ids)
    {
        auto itElement = std::find_if(oldList.begin(), oldList.end(), [id](const Object &obj) { return id == obj.id; });
        list.emplace_back(std::move(*itElement));
        oldList.erase(itElement);
    }
}
size_t getIntendedIndex(const std::vector<int> &ids, const Object &obj)
{
    auto itElement = std::find_if(ids.begin(), ids.end(), [obj](int id) { return id == obj.id; });
    return itElement - ids.begin();
}

void sortByIdVector(std::list<Object> &list, const std::vector<int> &ids)
{
     list.sort([&ids](const Object &lhs, const Object &rhs){ return getIntendedIndex(ids, lhs) < getIntendedIndex(ids, rhs); });
}
void sortByIdVector(std::vector<Object> &list, const std::vector<int> &ids)
{
     auto oldList = std::move(list);
     list = std::vector<Object>{};
     list.resize(oldList.size());
     for (Object &obj : oldList)
     {
         auto &newLocation = list[getIntendedIndex(ids, obj)];
         newLocation = std::move(obj);
     }
}
objectList.sort([&idList] (const Object& o1, const Object& o2) -> bool
   { return std::find(++std::find(idList.begin(), idList.end(), o1.id),
       idList.end(), o2.id)
       != idList.end();
   });
#include <iostream>
#include <string>
#include <list>
#include <algorithm>

struct Object {
    int id;
    string name;
};

int main()
{
  list<Object> objectList {{1, "one_1"}, {2, "two_1"}, {3, "three_1"}, {2, "two_2"}, {1, "one_2"}, {4, "four_1"}, {3, "Three_2"}, {4, "four_2"}};
  list<int> idList {3, 2, 4, 1};

  objectList.sort([&idList] (const Object& o1, const Object& o2) -> bool
    { return std::find(++std::find(idList.begin(), idList.end(), o1.id), idList.end(), o2.id) != idList.end(); });

  for(const auto& o: objectList) cout << o.id << " " << o.name << "\n";
}

/* OUTPUT: 
3 three_1
3 Three_2
2 two_1
2 two_2
4 four_1
4 four_2
1 one_1
1 one_2
*/