使用std::transform将std::vector<struct{key; val;}>转换为std::map<key, val>

3

考虑到这些类型:

struct ComplexLibraryThing { /*lots of fields*/};
typedef std::map<int, ComplexLibraryThing> MyMap;
struct ShadowComplexLibraryThing { /*Shadow of ComplexLibraryThing*/};
struct MyVecType { int a; ShadowComplexLibraryThing b; };
typedef std::vector<MyVecType> MyVector;

我可以为序列化做这件事情(我的序列化库不支持类似map的类型):

MyVecType map2pair(std::pair<int, ComplexLibraryThing> const &myPair)
{
    MyVecType retVal;
    retVal.a = myPair.first;
    retVal.b = convertForSerialisation(myPair.second);
    return retVal;
}

MyMap myMap = {...};
MyVector myVector;
std::transform(myMap.begin(),
               myMap.end(),
               std::back_inserter(myVector),
               map2pair);

我随后将该向量发送给想要重建 MyMap 的接收方。然而,我找不到一个适合像这样进行反序列化的 <algorithm> 模板:

MyMap myNewMap;
for (auto const &entry: myVector)
    myNewMap[entry.a] = convertForDeserialisation(entry.b);

如何使用<algorithm>编写这个代码?

(请注意,映射中的ComplexLibraryThing类型不能轻易更改,但我也有一个可以更改的ShadowComplexLibraryThing


1
为什么不在另一端使用相同的方法:使用函数的std::transform?或者将std::for_each()与lambda结合使用?我想我可能漏掉了什么 :-/ - piwi
你的修改并没有回答我的问题。你能修改MyVecType本身吗? - StoryTeller - Unslander Monica
如果您使用键和值作为其字段构造std::pair,则可以将其插入到映射中。这解决了您的问题吗? - Zalman Stern
所以,我并没有回答这个问题,但是顺便说一下... Google的protobuf序列化/反序列化工具支持map - druckermanly
2
顺便问一下,你想使用算法的原因是什么?对我来说,基于范围的for循环比transform简单得多。(特别是如果你将其更改为myNewMap.insert(std::make_pair(entry.a, convertForDeserialisation(entry.b));(这避免了默认构造映射条目然后再分配给它)。 - Martin Bonner supports Monica
显示剩余11条评论
2个回答

6
我认为缺少的关键“技巧”是std::inserter。这里是一个小演示。
#include <algorithm>
#include <iterator>
#include <map>
#include <vector>

struct foo {int a; int b;};

std::vector<foo> GenerateSource() {
  return {};
} 

std::pair<int, int> ConvertFooToMapPair(const foo& f) {
    return {f.a, f.b};
}

int main(int argc, char* argv[]) {
  std::map<int, int> destination;
  std::vector<foo> source = GenerateSource();
  std::transform(
    source.begin(), source.end(),
    std::inserter(destination, destination.end()),
    ConvertFooToMapPair);
}

4
此帖子展示了如何为std::map创建插入器:

如何向std::map插入元素?

迭代的对象类型需要是std::pair<KeyType, EntryType>(即所谓的std::mapvalue_type)。
我认为应该这样写:
std::pair<int, ComplexLibraryThing> vec2pair(const MyVecType &myVec)
{
    return std::make_pair(myVec.a,
                          transformForDeserialization(myVec.b));
}

MyVector myVector = {...};
MyMap myMap;
std::transform(myVector.begin(),
               myVector.end(),
               std::inserter(myMap, myMap.end()),
               vec2pair);

1
我认为 make_pair 需要改成 std::make_pair(myVec.a, transformForDeserialization(myVec.b)) - Martin Bonner supports Monica
比我快了两分钟,但我的想法完全一样! - druckermanly

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接