I have vectors and I would like to retrieve one vector that contains all entries which aren't duplicated anywhere in all input vectors.
#include <vector>
int main() {
std::vector<int> a = {2, 1, 3};
std::vector<int> b = {99, 1, 3, 5, 4};
std::vector<int> c = {5, 6, 7, 1};
// magic to retrieve {2, 99, 4, 6, 7} (order doesn't matter)
}
Is there a library function that can help performing this task efficiently?
I'm not tied to using vectors. The solution could include lists, sets, or whatever are most appropriate for the task.
Using unordered_map, O(N) space complexity and O(N) time complexity:
#include <vector>
#include <unordered_map>
#include <iostream>
std::vector<int>
get_unique_values(std::initializer_list<std::vector<int>> vectors)
{
std::unordered_map<int, size_t> tmp;
auto insert_value_in_tmp = [&tmp](int v) {
auto i = tmp.find(v);
if (i == tmp.end())
tmp[v] = 1;
else if (i->second != 2)
i->second = 2;
};
for ( auto& vec : vectors) {
for ( auto vec_value : vec ) {
insert_value_in_tmp(vec_value);
}
}
std::vector<int> result;
for (auto v : tmp) {
if (v.second == 1)
result.push_back(v.first);
}
return result;
};
int main() {
std::vector<int> a = {2, 1, 3};
std::vector<int> b = {99, 3, 5, 4};
std::vector<int> c = {5, 6, 7};
std::vector<int> result = get_unique_values({a,b,c});
for (auto v : result) {
std::cout << v << " ";
}
std::cout << '\n';
return 0;
}
Related
I want to iterate over single row and column in std::vector<std::vector<int>> matrix and get their sum.
I know that I can do this in nested loop, but here is my question. Can I use
int val_sum = 0;
std::for_each(matrix_[row].begin(),matrix_[row].end(),[&](int x) { val_sum += x;});
for columns and how to do that?
The analogous way of your proposal is to iterate the matrix rows and accumulate the elements in the given column.
int val_sum = 0;
std::for_each(matrix.begin(),matrix.end(),[&](std::vector<int> &row) { val_sum += row[column];});
But I would still prefer to use the c++11 range-loop version
int val_sum = 0;
for ( const std::vector<int> &row : matrix )
val_sum += row[column];
You can use nested std::accumulate:
#include <iostream>
#include <vector>
#include <numeric>
int main() {
std::vector<std::vector<int>> matrix = { {1, 2, 3}, {2, 3, 4}, {3, 4, 5} };
const int sum = std::accumulate(matrix.cbegin(), matrix.cend(), 0, [](const auto acc, const auto row) {
return acc + std::accumulate(row.cbegin(), row.cend(), 0);
});
std::cout << sum;
}
You could nest two for_each. You simply have to notice that every element of the outer for_each will be another vector<int>, a row. [Demo]
#include <algorithm> // for_each
#include <iostream> // cout
#include <vector>
int main()
{
std::vector<std::vector<int>> v{ {1, 2}, {3, 4}, {5, 6} };
std::for_each(std::cbegin(v), std::cend(v), [](auto& row) {
std::for_each(std::cbegin(row), std::cend(row), [](auto n) {
std::cout << n << " ";
});
std::cout << "\n";
});
}
If you want to sum all the elements of the matrix, you can use accumulate instead of the inner for_each loop. [Demo]
#include <algorithm> // for_each
#include <iostream> // cout
#include <numeric> // accumulate
#include <vector>
int main()
{
int result{};
std::vector<std::vector<int>> v{ {1, 2}, {3, 4}, {5, 6} };
std::for_each(std::cbegin(v), std::cend(v), [&result](auto& row) {
result += std::accumulate(std::cbegin(row), std::cend(row), 0);
});
std::cout << "sum = " << result << "\n";
}
Or even with two nested accumulate. [Demo]
#include <iostream> // cout
#include <numeric> // accumulate
#include <vector>
int main()
{
std::vector<std::vector<int>> v{ {1, 2}, {3, 4}, {5, 6} };
auto result = std::accumulate(std::cbegin(v), std::cend(v), 0, [](auto total, auto& row) {
return total + std::accumulate(std::cbegin(row), std::cend(row), 0);
});
std::cout << "sum = " << result << "\n";
}
If (after all, I misunderstood you from a beginning, and) you want to add all the elements of a given column. [Demo]
#include <iostream> // cout
#include <numeric> // accumulate
#include <vector>
int sum_column(const std::vector<std::vector<int>>& v, size_t column)
{
return std::accumulate(std::cbegin(v), std::cend(v), 0, [&column](auto total, auto& row) {
return total + row[column];
});
}
int main()
{
std::vector<std::vector<int>> v{ {1, 2}, {3, 4}, {5, 6} };
std::cout << "sum of column 1 = " << sum_column(v, 1) << "\n";
}
Is there any STL/Boost function in C++ that allows me to find the indices of all unique elements in a vector?
I have seen many solutons to find unique elements, but I need their index.
vector<int> v = { 1,1,1, 2,2,2,2, 3, 3, ,4,5,5,5,5,5,5 };// already sorted
Either I need first index of unique elemnt
vector<int> unique_index={0,3,7,9,10};
or I need last index of unique elements
vector<int> unique_index={2,6,8,9,15};
A simple way (aside from just keeping track of what the last element was) is to use a std::set to test if the current element is unique in the elements of the vector -- seen so far, and populate your unique indexes as you go. This provides a single pass through to collect the indexes where the first unique element is seen, e.g.
#include <iostream>
#include <vector>
#include <set>
int main (void) {
std::vector<int> v = { 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5 },
uniqueidx{};
std::set<int> s{};
for (size_t i = 0; i < v.size(); i++)
if (s.insert(v[i]).second)
uniqueidx.push_back(i);
for (const auto i : uniqueidx)
std::cout << i << '\n';
}
Example Use/Output
$ ./bin/set_index_of_unique_in_vector
0
3
7
10
11
(note: the last two values are 10 and 11, not 9 and 10 -- you are missing a value in your vector initialization, e.g. 3, ,4)
If you just wanted a simple-old loop to do the same thing, you could use:
#include <iostream>
#include <vector>
int main (void) {
std::vector<int> v = { 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5 },
uniqueidx{};
for (size_t i = 0; i < v.size(); i++)
if (!i || v[i-1] != v[i])
uniqueidx.push_back(i);
for (const auto i : uniqueidx)
std::cout << i << '\n';
}
(same output)
The benefit of the approach with std::set is you leave the determination of uniqueness up to std::set, with the simple loop -- it's up to you....
Look things over and let me know if you have questions.
Similar to David's answer of using std::set, you could also use std::map with its member function try_emplace(key, value):
#include <iostream>
#include <vector>
#include <map>
int main (void) {
std::vector<int> v = { 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5 };
std::map<int, int> m;
for (size_t i = 0; i < v.size(); i++)
{
// `i` is only entered if the `m[v[i]]` isn't filled yet.
m.try_emplace(v[i], i);
}
for (auto [valueFromV, indexFromV] : m)
{
std::cout << indexFromV << '\n';
}
}
you can change this code and using int instead of a string.
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <iterator>
#include <algorithm>
std::map<std::string, int> get_unique_indices(const std::vector<std::string>& products) {
std::vector<std::string> tempProducts(products);
std::map<std::string, int> result;
std::sort(std::begin(tempProducts), std::end(tempProducts));
for (auto it1 = std::begin(tempProducts), it2 = it1; it1 != std::end(tempProducts); it1 = it2) {
int duplication = 0;
for (; it2 != std::end(tempProducts) && (*it2 == *it1); ++it2) {
duplication++;
}
if (duplication == 1) {
result.insert({ *it1, std::find(std::begin(products), std::end(products), *it1) - std::begin(products) });
}
}
return result;
}
int main()
{
using namespace std;
vector<string> products = { "apple", "orange", "lemon", "apple", "kivi", "orange", "kivi", "melon"};
auto result = get_unique_indices(products);
for (const auto& [key, value] : result) {
std::cout << key << " " << value << std::endl;
}
return 0;
}
At first, I create another vector to save the original data. (Cause the position of the item will change in the sort method).
then I use two iterators to find duplicate items and count them. the result will be saved in a map instance.
this code must compile with c++17 onwards.
I am trying to replace the elements in a 2D vector (vector<vector<int>>). I want to change the elements not only by one value, but by a list, which means, for example, change 1,3,4,5,8,9 to 1,2,3,4,5,6 one-to-one correspondence. I have made a very slow code with double loops. Is there any way to speed up the process, with new function or sort the element? Because my 2D vector is very big, 3*300000 actually. My example code is below:
int myints[] = { 1,3,4,5,8,9 };
int myints2[] = { 1,2,3,4,5,6 };
std::vector<int> vals (myints, myints+6);
std::vector<int> vals2 (myints2, myints2+6);
vector<vector<int>> V0(3);
V0[0]={1,4,5};
V0[1]={3,1,8};
V0[2]={1,9,4};
for (size_t j = 0; j < V0.size(); j++)
{
for (int i = 0; i < vals.size(); i++)
replace(V0[j].begin(), V0[j].end(), vals[i], vals2[i]);
};
The ideal output V0 should be
1 3 4
2 1 5
1 6 3
You can use an unordered_map to replace each value directly, instead of searching through the whole vector for each replacement:
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
unordered_map<int, int> replacements{{1, 1}, {3, 2}, {4, 3}, {5, 4}, {8, 5}, {9, 6}};
vector<vector<int>> v0(3);
v0[0] = {1, 4, 5};
v0[1] = {3, 1, 8};
v0[2] = {1, 9, 4};
for_each(v0.begin(), v0.end(), [&](vector<int>& v)
{
transform(v.begin(), v.end(), v.begin(), [&](int val)
{
auto it = replacements.find(val);
return it != replacements.end() ? replacements[val] : val;
});
});
// Print
for (auto& v : v0)
{
cout << "[ ";
for (auto val : v)
{
cout << val << ", ";
}
cout << "]" << endl;
}
return 0;
}
Output:
[ 1, 3, 4, ]
[ 2, 1, 5, ]
[ 1, 6, 3, ]
In C++17, you may also choose a parallel execution policy in for_each and/or transform, since all the changes can be done in parallel.
I have a vector of vectors and I want to take the contents of it into a single column vector. i.e.,
input: A = [[1 2] [3 4]]
output: v = [[1][2][3][4]] (column vector)
Is there a quick way of doing this in C++?
Like this:
std::vector<std::vector<int>> a = {{1, 2}, {3, 4}};
std::vector<std::vector<int>> b;
for ( auto& row : a )
{
for ( auto item: row )
{
b.push_back(std::vector<int>{item});
}
}
Unfortunately I have to tell you, that every other answer, at least until now, is not as good as it seems.
Let us step through the answers; in the end I tell you how to handle it properly.
std::vector<std::vector<int>> v = {{1, 2, 3}, {2, 2, 3}};
std::vector<int> b;
for(auto& vec : v){
std::copy(vec.begin(), vec.end(), std::back_inserter(b)); // performes single insertion at the end
}
std::copy is bad style for inserting into a std::vector. You insert it value by value at the end of the destination vector. This means potentially more reallocations and moves/copies as needed.
std::vector<std::vector<int>> vv = { { 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 } };
std::vector<int> v;
for (auto row : vv) {
for (auto el : row) {
v.push_back(el);
}
}
Same here. You resize it at every push_back, that is absolutely not necessary!
I recommend you the use of std::vector::insert. It performs some internal resizes by its own.
std::vector<std::vector<int>> v = {{1, 2, 3}, {2, 2, 3}};
std::vector<int> b;
for(auto& vec : v){
b.insert(std::cend(b), std::cbegin(vec), std::cend(vec));
}
This solution performs a resize before any insertion occurs. This will result in the best possible performance.
Here some testcode. Try it by your own:
#include <vector>
#include <chrono>
#include <iostream>
int main()
{
std::vector<int> v(100'000'000, 5);
auto start = std::chrono::steady_clock::now();
std::vector<int> b;
b.insert(std::cend(b), std::cbegin(v), std::cend(v));
auto end = std::chrono::steady_clock::now();
std::cout << "insert durtion:\t" << (end - start).count() << std::endl;
b = std::vector<int>();
start = std::chrono::steady_clock::now();
std::copy(std::cbegin(v), std::cend(v), std::back_inserter(b));
end = std::chrono::steady_clock::now();
std::cout << "copy durtion:\t" << (end - start).count() << std::endl;
b = std::vector<int>();
start = std::chrono::steady_clock::now();
for (auto el : v)
b.push_back(el);
end = std::chrono::steady_clock::now();
std::cout << "copy durtion:\t" << (end - start).count() << std::endl;
std::cin.ignore();
return 0;
}
This produces in x64 release in this output:
insert durtion: 132388657
copy durtion: 844505239
push_back durtion: 866565409
In the end, you could of course resize the vector first and then start the copy, but I think that's the wrong way to deal with that, if in fact, the std::vector already offers us this solution.
You could std::copy every row using std::back_inserter like so:
int main()
{
std::vector<std::vector<int>> v = {{1, 2, 3}, {2, 2, 3}};
std::vector<int> b;
for(auto& vec : v){
std::copy(vec.begin(), vec.end(), std::back_inserter(b));
}
}
If you want to copy all the elements from a vector of vectors into a single vector then utilize the two loops:
std::vector<std::vector<int>> vv = { { 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 } };
std::vector<int> v;
for (auto row : vv) {
for (auto el : row) {
v.push_back(el);
}
}
//print out the vector:
for (auto el : v) {
std::cout << el << ' ';
}
or utilize the std::copy function.
I have the vector that defines the order of items (0..N-1), e.g.
{5, 0, 4, 3, 2, 1, 7, 6}.
I have to sort subsets of that vector. So, for {0, 1, 2, 5} I should get {5, 0, 2, 1}.
I tested the following solutions:
Create a set of items in a subset, then clear the subset, go through the ordering vector, adding only items in the set.
Create new sorted vector by going through the ordering vector, adding only items found by in the subset by std::lower_bound.
The second solution seems much faster, although it needs subset to be sorted. Are there any better solutions? I am using C++/STL/Qt, but the problem is probably not language-dependent.
Check this code :-
#include <iostream>
#include <algorithm>
#include <vector>
struct cmp_subset
{
std::vector<int> vorder;
cmp_subset(const std::vector<int>& order)
{
vorder.resize(order.size());
for (int i=0; i<order.size(); ++i)
vorder.at(order[i]) = i;
}
bool operator()(int lhs, int rhs) const
{
return vorder[lhs] < vorder[rhs];
}
};
int main()
{
std::vector<int> order = {5, 0, 4, 3, 2, 1, 7, 6};
std::vector<int> subset = {0, 1, 2, 5};
for (auto x : subset)
std::cout << x << ' ';
std::cout << '\n';
std::sort(subset.begin(), subset.end(), cmp_subset(order));
for (auto x : subset)
std::cout << x << ' ';
std::cout << '\n';
return 0;
}
The code is copied from here