итератор для вставки в другой контейнер в зависимости от предиката - PullRequest
1 голос
/ 12 апреля 2020

Допустим, у меня есть вектор чисел, и я хочу создать два вектора, чтобы разделить числа на нечетные и четные. Легко с простой для:

std::vector<int> odds;
std::vector<int> evens;
std::vector<int> numbers;
for (int number : numbers) {
    if isOdd(number)
        odds.push_back(number);
    else
        evens.push_back(number);
}

Я хотел бы знать, есть ли какой-нибудь insertter_iterator, который может сделать это, чтобы я мог написать что-то вроде

std::vector<int> odds;
std::vector<int> evens;
std::vector<int> numbers;

auto pred = [](int i) { return isOdd(i) ? True : False;};
auto identity = [](int i) {return i;};
std::transform(std::begin(numbers), std::end(numbers), some_inserter(odd, evens, pred), identity);

Это просто из любопытства я пытаюсь узнать, как работают алгоритмы и итераторы. Также возможно решение на основе диапазонов.

Ответы [ 2 ]

2 голосов
/ 12 апреля 2020

Вы можете использовать алгоритм std::partition_copy следующим образом https://en.cppreference.com/w/cpp/algorithm/partition_copy

int main() {
    std::vector vec = {1, 2, 3, 4, 5, 6};//the vector to be partitioned
    std::vector<int> odds(vec.size());//will hold odds (to have the sam size as the original (the maximum case) )
    std::vector<int> evens(vec.size());//will hold evens

    auto [oddsEnd, evensEnd] =
            std::partition_copy(vec.begin(), vec.end(), odds.begin(), evens.begin(), [](int i){return i%2!=0;});//will copy at the front (won't insert at the back)
    odds.erase(oddsEnd, odds.end());//to erase the undesired excess
    evens.erase(evensEnd, evens.end());//to erase the undesired excess

}

ИЛИ использовать std::back_inserter https://en.cppreference.com/w/cpp/iterator/back_inserter (см. Комментарии)

int main() {
    std::vector vec = {1, 2, 3, 4, 5, 6};//the vector to be partitioned
    std::vector<int> odds;//will hold odds
    std::vector<int> evens;//will hold evens

    std::partition_copy(vec.begin(), vec.end(), std::back_inserter(odds), std::back_inserter(evens), [](int i){return i%2!=0;});//will insert

}
0 голосов
/ 12 апреля 2020

Вы можете просто использовать for_each, который можно использовать почти так же, как вы описали:

std::vector<int> odds;
std::vector<int> evens;
std::vector<int> numbers;

auto pred = [](int i) { return i % 2;};
auto identity = [](int i) {return i;};

std::for_each(std::begin(numbers), std::end(numbers), [&](int number) mutable {
    int iden = identity(number);
    if (pred(iden)) odds.push_back(iden);
    else evens.push_back(iden);
});

// Or with range-based loop:

for (auto &elem : numbers) {
    if (pred(iden)) odds.push_back(iden);
    else evens.push_back(iden);
}
...