Test results on my machine (100 million ints in the array):
checkpoint
starting test: approach1
test took: 84ms
starting test: approach2
test took: 190ms
starting test: approach3
test took: 529ms
starting test: Bathsheba's idea
test took: 61ms
Incidentally, writing idiomatic code is often the most efficient of all. clang, gcc et. al. optimisers are fantastic:
void approach5(std::vector<int> &nums) {
auto filter = [](auto x) { return (x < 10) ? 0 : x; };
auto grow = [filter](auto x) { return filter(x * x); };
std::transform(begin(nums), end(nums), begin(nums), grow);
}
Here's the code.
#include <iostream>
#include <chrono>
#include <random>
#include <array>
#include <vector>
#include <algorithm>
auto constexpr test_size = std::size_t(100'000'000);
using namespace std::literals;
void approach1(std::vector<int> &nums) {
for (unsigned int i = 0; i < nums.size(); ++i) {
nums[i] *= nums[i];
if (nums[i] < 10) {
nums[i] = 0;
}
}
}
void approach2(std::vector<int> &nums) {
for (unsigned int i = 0; i < nums.size(); ++i) {
nums[i] *= nums[i];
}
for (unsigned int i = 0; i < nums.size(); ++i) {
if (nums[i] < 10) {
nums[i] = 0;
}
}
}
void approach3(std::vector<int> &nums) {
std::vector<int> flags;
flags.resize(nums.size());
for (unsigned int i = 0; i < nums.size(); ++i) {
nums[i] *= nums[i];
flags[i] = nums[i] < 10;
}
for (unsigned int i = 0; i < flags.size(); ++i) {
nums[i] = (!flags[i]) * nums[i]; //!flags[i] is 0 if nums[i] < 10
}
}
void approach4(std::vector<int> &nums) {
for (std::size_t i = 0; i < nums.size(); ++i) {
nums[i] *= (nums[i] <= 3 ? 0 : nums[i]);
}
}
auto test = [](auto &&name, auto &&approach, auto &&data) {
std::cout << "starting test: " << name << std::endl;
auto my_data = std::vector<int>(data.begin(), data.end());
auto now = std::chrono::high_resolution_clock::now();
approach(my_data);
auto then = std::chrono::high_resolution_clock::now();
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(then - now);
std::cout << "test took: " << diff.count() << "ms" << std::endl;
};
std::array<int, test_size> test_data;
int main() {
std::random_device rd;
std::default_random_engine eng(rd());
std::uniform_int_distribution<> dist(0, 100);
std::generate(test_data.begin(), test_data.end(), [&]() { return dist(eng); });
std::cout << "checkpoint" << std::endl;
test("approach1", approach1, test_data);
test("approach2", approach2, test_data);
test("approach3", approach3, test_data);
test("Bathsheba's idea", approach4, test_data);
}