C++ 替换循环以插入和更新标准库的集合

C++ 替换循环以插入和更新标准库的集合,c++,stl,C++,Stl,我有两个循环来迭代集合: // 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

我有两个循环来迭代集合:

// 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); });
第一个将缺少的元素添加到集合中。 第二个将现有实例更新到集合中。 如何用标准库函数替换循环

// 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);
}
这个问题是解决这个问题的进一步步骤

下面是一个完整的示例,其中包括:

#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;
    }
}
#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;
    }
}

也许类似的东西也能起作用,我还没有测试过:

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;
    });

还有什么理由不向CNode构造函数添加objectType参数吗?

如果有人有兴趣获得函数的完整代码,请在最终解决方案下方使用标准库替换两个循环以插入和更新集合:

// 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") {}    
    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;
    }
}
#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;
    }
}

我在向CNode-ctor添加objectType参数方面没有问题,但我不确定下一步该怎么做。