заменить все нечетные значения в векторе на базовое значение из нового вектора - PullRequest
7 голосов
/ 19 февраля 2020

Учитывая следующие векторы:

std::vector<int> foo{1,2,3,4,5,6,7};
std::vector<int> bar{10,20,30,40,50,60,70};

В конце я хочу, чтобы foo содержал значения { 10, 2, 30, 4, 50, 6, 70 }, означающие замену всех нечетных значений.

Я пробовал алгоритм std: : replace_if, но как получить доступ к барам, соответствующим значению?

// replace_copy_if example
#include <iostream>     // std::cout
#include <algorithm>    // std::replace_copy_if
#include <vector>       // std::vector

bool IsOdd (int i) { return ((i%2)==1); }

int main () {
  std::vector<int> foo{1,2,3,4,5,6,7};
  std::vector<int> bar{10,20,30,40,50,60,70};

  std::replace_if (foo.begin(), foo.end(), IsOdd, 0);

  std::cout << "foo contains:";
  for (auto i: foo){ std::cout << ' ' << i; }
  std::cout << '\n';

  return 0;
}

// output         : foo contains: 0 2 0 4 0 6 0
// desired output : foo contains: 10 2 30 4 50 6 70

Ответы [ 5 ]

8 голосов
/ 19 февраля 2020

Можно использовать перегрузку std::transform, которая принимает два диапазона входных итераторов:

std::transform(foo.begin(), foo.end(), bar.begin(), foo.begin(),
  [](auto const& a, auto const& b) {
     if (a % 2)
        return b;
     return a; 
  }
);
2 голосов
/ 19 февраля 2020

Добавляя ответы здесь, вы можете создать собственную функцию:

Демо: https://godbolt.org/z/yf3jYx

void IsOdd (const std::vector<int>& a, std::vector<int>& b) { 
    for(size_t i = 0; i < a.size() && i < b.size(); i++){
        if(b[i] % 2 == 1)
            b[i] = a[i];
    }
}

и вызвать ее в основном:

IsOdd(bar, foo);
1 голос
/ 19 февраля 2020

std::replace_if поддерживает только замену элементов постоянным значением, указанным в качестве последнего аргумента. Однако, если вы чувствуете, что это имеет какой-то смысл для вас, вы можете написать свою собственную replace_if функцию на основе эталонной реализации и заставить ее принимать какой-то генератор в качестве последнего параметра. Например:

template<class ForwardIt, class UnaryPredicate, class Generator>
void my_replace_if(ForwardIt first, ForwardIt last,
                UnaryPredicate p, Generator g)
{
    for (; first != last; ++first) {
        if(p(*first)) {
            *first = g();
        }
    }
}

bool IsOdd (int i) { return ((i%2)==1); }

int main(int argc, const char * argv[]) {
    std::vector<int> foo{1,2,3,4,5,6,7};
    std::vector<int> bar{10,20,30,40,50,60,70};
    int i = 0;
    my_replace_if (foo.begin(), foo.end(), IsOdd, [&bar, &i]()
        {
            return bar[i++];
        });
    for (auto el : foo)
    {
        std::cout << el << std::endl;
    }
    return 0;
}

===== EDIT =====

Как указывает anastaciu, индекс генератора должен увеличиваться с каждым шагом, а не только когда генератор

Например:

    my_replace_if (foo.begin(), foo.end(),
        [&i](int v) { i++; return ((v%2)==1); },
        [&bar, &i]() { return bar[i-1]; });

Но, если честно, в данном случае это действительно излишне, и это даже не выглядит красиво.

1 голос
/ 19 февраля 2020

Вы можете использовать std::transform:

std::vector<int> result;

std::transform(
    foo.begin(), foo.end(), bar.begin(),
    std::back_inserter(result),
    [](const auto& a, const auto& b) {
        if (a % 2 == 0) {
            return a;
        }
        return b;
    }
);

Демо

1 голос
/ 19 февраля 2020
// replace_copy_if example
#include <iostream>     // std::cout
#include <vector>       // std::vector

int main () {
  std::vector<int> foo{1,2,3,4,5,6,7};
  std::vector<int> bar{10,20,30,40,50,60,70};

  for (size_t i = 0; i < bar.size(); i++)
  {
     if (foo[i]%2==1) foo[i]=bar[i];
  }


  std::cout << "bar contains:";
  for (auto i: foo){ std::cout << ' ' << i; }
  std::cout << '\n';

  return 0;
}
...