Copy Elements and Ranges
You can copy ranges forward with std::copy
, backward with std::copy_backward
and conditionally with std::copy_if
. If you want to copy n elements, you can use std::copy_n
.
std::vector<int> myVec{0, 1, 2, 3, 4, 5, 6, 7, 9};
std::vector<int> myVec2(10);
std::copy_if(myVec.begin(), myVec.end(), myVec2.begin()+3,
[](int a){ return a%2; });
for (auto v: myVec2) std::cout << v << " "; // 0 0 0 1 3 5 7 9 00
std::string str{"abcdefghijklmnop"};
std::string str2{"---------------------"};
std::cout << str2; // ---------------------
std::copy_backward(str.begin(), str.end(), str2.end());
std::cout << str2; // -----abcdefghijklmnop
std::cout << str; // abcdefghijklmnop
std::copy_backward(str.begin(), str.begin() + 5, str.end());
std::cout << str; // abcdefghijkabcde
Replace Elements and Ranges
You have with std::replace
, std::replace_if
, std::replace_copy
and std::replace_copy_if
four variations to replace elements in a range. The algorithms differ in two aspects. First, does the algorithm need a predicate? Second, does the algorithm copy the elements in the destination range?
std::string str{"Only for testing purpose."};
std::replace(str.begin(), str.end(), ' ', '1');
std::cout << str; // Only1for1testing1purpose.
std::replace_if(str.begin(), str.end(), [](char c){ return c == '1'; }, '2');
std::cout << str; // Only2for2testing2purpose.
std::string str2;
std::replace_copy(str.begin(), str.end(), std::back_inserter(str2), '2', '3');
std::cout << str2; // Only3for3testing3purpose.
std::string str3;
std::replace_copy_if(str2.begin(), str2.end(),
std::back_inserter(str3), [](char c){ return c == '3'; }, '4');
std::cout << str3; // Only4for4testing4purpose.
Remove Elements and Ranges
The four variations std::remove, std::remove_if, std::remove_copy
and std::remove_copy_if
support two kinds of operations. On one hand, remove elements with and without a predicate from a range. On the other hand, copy the result of your modification to a new range.
std::vector<int> myVec{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
auto newIt= std::remove_if(myVec.begin(), myVec.end(),
[](int a){ return a%2; });
for (auto v: myVec) std::cout << v << " "; // 0 2 4 6 8 5 6 7 8 9
myVec.erase(newIt, myVec.end());
for (auto v: myVec) std::cout << v << " "; // 0 2 4 6 8
std::string str{"Only for Testing Purpose."};
str.erase( std::remove_if(str.begin(), str.end(),
[](char c){ return std::isupper(c); }, str.end() ) );
std::cout << str << std::endl; // nly for esting urpose.
Fill and Create Ranges
You can fill a range with std::fill
and std::fill_n
; you can generate new elements with std::generate
and std::generate_n
.
int getNext(){
static int next{0};
return ++next;
}
std::vector<int> vec(10);
std::fill(vec.begin(), vec.end(), 2011);
for (auto v: vec) std::cout << v << " ";
// 2011 2011 2011 2011 2011 2011 2011 2011 2011 2011
std::generate_n(vec.begin(), 5, getNext);
for (auto v: vec) std::cout << v << " ";
// 1 2 3 4 5 2011 2011 2011 2011 2011
Move Ranges
std::move
moves the ranges forward; std::move_backward
moves the ranges backwards.
std::vector<int> myVec{0, 1, 2, 3, 4, 5, 6, 7, 9};
std::vector<int> myVec2(myVec.size());
std::move(myVec.begin(), myVec.end(), myVec2.begin());
for (auto v: myVec2) std::cout << v << " "; // 0 1 2 3 4 5 6 7 9 0
std::string str{"abcdefghijklmnop"};
std::string str2{"---------------------"};
std::move_backward(str.begin(), str.end(), str2.end());
std::cout << str2; // -----abcdefghijklmnop
Swap Ranges
std::swap
and std::swap_ranges
can swap objects and ranges.
std::vector<int> myVec{0, 1, 2, 3, 4, 5, 6, 7, 9};
std::vector<int> myVec2(9);
std::swap(myVec, myVec2);
for (auto v: myVec) std::cout << v << " "; // 0 0 0 0 0 0 0 0 0
for (auto v: myVec2) std::cout << v << " "; // 0 1 2 3 4 5 6 7 9
std::string str{"abcdefghijklmnop"};
std::string str2{"---------------------"};
std::swap_ranges(str.begin(), str.begin()+5, str2.begin()+5);
std::cout << str << std::endl; // -----fghijklmnop
std::cout << str2 << std::endl; // -----abcde-----------
Transform Ranges
The std::transform
algorithm applies a unary or binary callable to a range and copies the modified elements to the destination range.
std::string str{"abcdefghijklmnopqrstuvwxyz"};
std::transform(str.begin(), str.end(), str.begin(),
[](char c){ return std::toupper(c); });
std::cout << str; // ABCDEFGHIJKLMNOPQRSTUVWXYZ
std::vector<std::string> vecStr{"Only", "for", "testing", "purpose", "."};
std::vector<std::string> vecStr2(5, "-");
std::vector<std::string> vecRes;
std::transform(vecStr.begin(), vecStr.end(),
vecStr2.begin(), std::back_inserter(vecRes),
[](std::string a, std::string b){ return std::string(b)+a+b; });
for (auto str: vecRes) std::cout << str << " ";
// -Only- -for- -testing- -purpose- -.-
Reverse Ranges
std::reverse
and std::reverse_copy
invert the order of the elements in their range.
std::string str{"123456789"};
std::reverse(str.begin(), str.begin()+5);
std::cout << str; // 543216789
Randomly Shuffle Ranges
You can randomly shuffle ranges with std::random_shuffle
and std::shuffle
.
using std::chrono::system_clock;
using std::default_random_engine;
std::vector<int> vec1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
std::vector<int> vec2(vec1);
std::random_shuffle(vec1.begin(), vec1.end());
for (auto v: vec1) std::cout << v << " "; // 4 3 7 8 0 5 2 1 6 9
unsigned seed= system_clock::now().time_since_epoch().count();
std::shuffle(vec2.begin(), vec2.end(), default_random_engine(seed));
for (auto v: vec2) std::cout << v << " "; // 4 0 2 3 9 6 5 1 8 7
Remove Duplicates
With the algorithms std::unique
and std::unique_copy
you have more opportunities to remove adjacent duplicates. This can be done with and without a binary predicate.
std::vector<int> myVec{0, 0, 1, 1, 2, 2, 3, 4, 4, 5,
3, 6, 7, 8, 1, 3, 3, 8, 8, 9};
myVec.erase(std::unique(myVec.begin(), myVec.end()), myVec.end());
for (auto v: myVec) std::cout << v << " "; // 0 1 2 3 4 5 3 6 7 8 1 3 8 9
std::vector<int> myVec2{1, 4, 3, 3, 3, 5, 7, 9, 2, 4, 1, 6, 8,
0, 3, 5, 7, 8, 7, 3, 9, 2, 4, 2, 5, 7, 3};
std::vector<int> resVec;
resVec.reserve(myVec2.size());
std::unique_copy(myVec2.begin(), myVec2.end(), std::back_inserter(resVec),
[](int a, int b){ return (a%2) == (b%2); } );
for(auto v: myVec2) std::cout << v << " ";
// 1 4 3 3 3 5 7 9 2 4 1 6 8 0 3 5 7 8 7 3 9 2 4 2 5 7 3
for(auto v: resVec) std::cout << v << " "; // 1 4 3 2 1 6 3 8 7 2 5
Partition
std::partition
and std::stable_partition
partition a range and returns the partition point. With std::partition_point
you can get the partition point of a partition. Afterwards you can check the partition with std::is_partitioned
or copy it with std::partition_copy
.
bool isOdd(int i){ return (i%2) == 1; }
vector<int> vec{1, 4, 3, 4, 5, 6, 7, 3, 4, 5, 6, 0, 4,
8, 4, 6, 6, 5, 8, 8, 3, 9, 3, 7, 6, 4, 8};
auto parPoint= partition(vec.begin(), vec.end(), isOdd);
for (auto v: vec) cout << v << " ";
// 1 7 3 3 5 9 7 3 3 5 5 0 4 8 4 6 6 6 8 8 4 6 4 4 6 4 8
for (auto v= vec.begin(); v != parPoint; ++v) cout << *v << " ";
// 1 7 3 3 5 9 7 3 3 5 5
for (auto v= parPoint; v != vec.end(); ++v) cout << *v << " ";
// 4 8 4 6 6 6 8 8 4 6 4 4 6 4 8
cout << is_partitioned(vec.begin(), vec.end(), isOdd); // true
list<int> le;
list<int> ri;
partition_copy(vec.begin(), vec.end(), back_inserter(le), back_inserter(ri),
[](int i) { return i < 5; });
for (auto v: le) cout << v << " "; // 1 3 3 3 3 0 4 4 4 4 4 4
for (auto v: ri) cout << v << " "; // 7 5 9 7 5 5 8 6 6 6 8 8 6 6 8