Desafio C++

Filtrar, transformar e acumular em pipeline

Enunciado

Dado um vetor de inteiros, use std::find_if para localizar o primeiro número maior que 5, depois use std::transform para converter todos os números a partir desse ponto em seus dobros, e finalmente std::accumulate para somar os valores transformados. Imprima o vetor original após a transformação e a soma.

Requisitos

  • Use std::find_if para achar o iterador do primeiro elemento > 5.
  • Use std::transform para dobrar os elementos do intervalo encontrado até o fim.
  • Use std::accumulate para somar os elementos transformados.
  • Imprima o vetor modificado e a soma no formato 'Soma: X'.

Código inicial

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>

int main() {
    std::vector<int> nums = {2, 8, 1, 6, 3, 9};
    // TODO: encontre, transforme e acumule
    return 0;
}

Saída esperada

Vetor modificado: 2 16 1 12 3 18 
Soma: 46
Ver dica

O iterador retornado por find_if pode ser usado como início do intervalo em transform e accumulate.

Mostrar solução
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>

int main() {
    std::vector<int> nums = {2, 8, 1, 6, 3, 9};

    // 1. Encontra o primeiro número maior que 5
    auto it = std::find_if(nums.begin(), nums.end(),
                           [](int n) { return n > 5; });

    if (it != nums.end()) {
        // 2. Dobra todos os elementos a partir de 'it'
        std::transform(it, nums.end(), it,
                       [](int n) { return n * 2; });

        // 3. Soma os elementos transformados (de 'it' até o fim)
        int soma = std::accumulate(it, nums.end(), 0);

        std::cout << "Vetor modificado: ";
        for (int n : nums) std::cout << n << ' ';
        std::cout << '\n';
        std::cout << "Soma: " << soma << '\n';
    } else {
        std::cout << "Nenhum número maior que 5\n";
    }

    return 0;
}

Passo a passo

  1. Incluímos os cabeçalhos necessários: <algorithm> para find_if e transform, <numeric> para accumulate.
  2. std::find_if percorre nums e retorna um iterador para o primeiro valor > 5 (o 8).
  3. Verificamos se o iterador é válido (it != nums.end()); se não for, não há o que transformar.
  4. std::transform(it, nums.end(), it, ...) aplica n * 2 no próprio vetor, do ponto encontrado até o fim. Isso modifica os elementos 8, 6 e 9 para 16, 12 e 18.
  5. std::accumulate(it, nums.end(), 0) soma apenas os elementos transformados: 16 + 12 + 18 = 46.
  6. Imprimimos o vetor completo (modificado) e a soma.

Por que funciona

find_if fornece um iterador que delimita o início do subintervalo de interesse. transform e accumulate aceitam esse iterador como parte do intervalo, permitindo operar apenas nos elementos a partir dele. Isso mostra como algoritmos da STL se compõem naturalmente, sem laços manuais e sem índices propensos a erro.

Erros comuns

  • Passar it como destino em transform sem verificar se é válido: se it == end(), o intervalo é vazio e nada acontece, mas é seguro; porém, se você tentar acessar *it antes, é comportamento indefinido.
  • Usar std::accumulate(nums.begin(), nums.end(), 0) em vez de começar de it: somaria todos os elementos, não apenas os transformados.
  • Esquecer que transform com o mesmo iterador de entrada e saída é permitido e eficiente, mas exige que a operação não dependa de outros elementos.

Outra forma de resolver

Você poderia usar um laço for com iteradores para modificar e somar, mas perderia a clareza e a segurança dos algoritmos. Outra alternativa é usar std::for_each para modificar e depois accumulate, mas transform é mais direto para mapeamento.

Saída esperada

Vetor modificado: 2 16 1 12 3 18 
Soma: 46