我有两个循环来迭代集合:
如何用标准库函数替换循环?
// add missing elements into the collection (if any)
for (auto i = collection.size(); i < objectTypes.size() + startIdx; i++)
{
collection.push_back(CNode(i));
}
// update elements of the collection
for (const auto& objectType : objectTypes)
{
collection[startIdx++].SetObjectType(objectType);
}
这个问题是this one的又一步。
这里有一个完整的样本编译:
#include <string>
#include <iostream>
#include <vector>
#include <regex>
class CObject
{
std::string _objectType;
public:
CObject() : _objectType("n/a") {}
void SetObjectType(std::string objectType) { _objectType = objectType; }
std::string GetObjectType() const { return _objectType; }
};
class CNode
{
int _id;
CObject _object;
public:
explicit CNode(int id) : _id(id) {}
void SetObjectType(std::string objectType) { _object.SetObjectType(objectType); }
std::string GetObjectType() const { return _object.GetObjectType(); }
};
std::vector<std::string> SplitLine(std::string const& line, std::string seps)
{
std::regex regxSeps(seps); // the dot character needs to be escaped in a regex
std::sregex_token_iterator rit(line.begin(), line.end(), regxSeps, -1);
return std::vector<std::string>(rit, std::sregex_token_iterator());
}
static int ParseLine(std::string line, std::string seps, size_t startIdx, std::vector<CNode>& collection)
{
if (startIdx > collection.size())
{
throw std::invalid_argument("the start index is out of range");
}
auto objectTypes = SplitLine(line, seps);
for (auto missingIdx = collection.size(); missingIdx < objectTypes.size() + startIdx; missingIdx++)
{
collection.push_back(CNode(missingIdx));
}
for (const auto& objectType : objectTypes)
{
collection[startIdx++].SetObjectType(objectType);
}
return (startIdx - 1);
}
int main()
{
std::string seps = "\\."; // the dot character needs to be escaped in a regex
// 2 3 4 5 6 7 8 9
std::string line = "abc.def.ghi.klm.nop.qrs.tuv.wxyz";
std::vector<CNode> collection{ CNode(0), CNode(1), CNode(2) , CNode(3) , CNode(4) , CNode(5) };
auto startAt = 2;
try
{
auto collection_size = ParseLine(line, seps, startAt, collection);
std::cout << collection_size << std::endl;
for (auto value : collection)
{
std::cout << value.GetObjectType() << std::endl;
}
}
catch (std::invalid_argument& e)
{
std::cout << " out of range exception " << e.what() << std::endl;
}
}
答案 0 :(得分:1)
也许与此类似的东西可行(我还没有测试过):
auto i = collection.size();
std::transform (objectTypes.begin(), objectTypes.end(),
std::back_inserter(collection),
[&](const ObjectType& ot) {
CNode ct(++i);
ct.SetObjectType(ot);
return ct;
});
是否还有任何理由不将objectType参数添加到CNode构造函数中?
答案 1 :(得分:0)
如果有人有兴趣获取该函数的完整代码,请在最终解决方案下使用标准库替换两个循环以插入和更新集合:
// Compute the number of elements to insert and to update
auto numInserts = startIdx + objectTypes.size() - collection.size();
auto numUpdates = collection.size() - startIdx;
// update the elements that already exists in the collection
std::for_each( objectTypes.begin(),
objectTypes.begin() + numUpdates,
[&](const std::string objectType)
{ collection[startIdx++].SetObjectType(objectType); });
// add the missing elements into the collection (if any)
std::transform( objectTypes.end() - numInserts,
objectTypes.end(),
std::back_inserter(collection),
[&](const std::string& objectType)
{ return CNode(++startIdx, objectType); });
这里有一个完整的样本编译:
#include <string>
#include <iostream>
#include <vector>
#include <regex>
class CObject
{
std::string _objectType;
public:
CObject() : _objectType("n/a") {}
explicit CObject(std::string objectType) : _objectType(objectType) {};
void SetObjectType(std::string objectType) { _objectType = objectType; }
std::string GetObjectType() const { return _objectType; }
};
class CNode
{
int _id;
CObject _object;
public:
explicit CNode(int id) : _id(id) {}
explicit CNode(int id, std::string objectType) : _id(id), _object(objectType) {}
void SetObjectType(std::string objectType) { _object.SetObjectType(objectType); }
std::string GetObjectType() const { return _object.GetObjectType(); }
};
std::vector<std::string> SplitLine(std::string const& line, std::string seps)
{
std::regex regxSeps(seps); // the dot character needs to be escaped in a regex
std::sregex_token_iterator rit(line.begin(), line.end(), regxSeps, -1);
return std::vector<std::string>(rit, std::sregex_token_iterator());
}
static int ParseLineWithLoops(std::string line, std::string seps, size_t startIdx, std::vector<CNode>& collection)
{
if (startIdx > collection.size())
{
throw std::invalid_argument("the start index is out of range");
}
auto objectTypes = SplitLine(line, seps);
// expand the collection if needed
for (auto idx = collection.size(); idx < objectTypes.size() + startIdx; idx++)
{
collection.push_back(CNode(idx));
}
// update the types of elements into the collection
for (const auto& objectType : objectTypes)
{
collection[startIdx++].SetObjectType(objectType);
}
return (startIdx - 1);
}
static int ParseLineWithStdTransform(std::string line, std::string seps, size_t startIdx, std::vector<CNode>& collection)
{
if (startIdx > collection.size())
{
throw std::invalid_argument("the start index is out of range");
}
auto objectTypes = SplitLine(line, seps);
// Compute the number of elements to insert and to update
auto numInserts = startIdx + objectTypes.size() - collection.size();
auto numUpdates = collection.size() - startIdx;
// update the elements that already exists in the collection
std::for_each( objectTypes.begin(),
objectTypes.begin() + numUpdates,
[&](const std::string objectType) { collection[startIdx++].SetObjectType(objectType); });
// add the missing elements into the collection (if any)
std::transform( objectTypes.end() - numInserts,
objectTypes.end(),
std::back_inserter(collection),
[&](const std::string& objectType) { return CNode(++startIdx, objectType); });
return (collection.size() - 1);
}
int main()
{
std::string seps = "\\."; // the dot character needs to be escaped in a regex
// 2 3 4 5 6 7 8 9
std::string line = "abc.def.ghi.klm.nop.qrs.tuv.wxyz";
auto startAt = 2;
std::vector<CNode> collection1{ CNode(0), CNode(1), CNode(2) , CNode(3) , CNode(4) , CNode(5) };
try
{
auto collection_size = ParseLineWithStdTransform(line, seps, startAt, collection1);
std::cout << collection_size << std::endl;
for (auto value : collection1)
{
std::cout << value.GetObjectType() << std::endl;
}
}
catch (std::invalid_argument& e)
{
std::cout << " out of range exception " << e.what() << std::endl;
}
std::vector<CNode> collection2{ CNode(0), CNode(1), CNode(2) , CNode(3) , CNode(4) , CNode(5) };
try
{
auto collection_size = ParseLineWithLoops(line, seps, startAt, collection2);
std::cout << collection_size << std::endl;
for (auto value : collection2)
{
std::cout << value.GetObjectType() << std::endl;
}
}
catch (std::invalid_argument& e)
{
std::cout << " out of range exception " << e.what() << std::endl;
}
}