Related
If I have a vector of values and want to check that they are all the same, what is the best way to do this in C++ efficiently? If I were programming in some other language like R one way my minds jumps to is to return only the unique elements of the container and then if the length of the unique elements is more than 1, I know all the elements cannot be the same. In C++ this can be done like this:
//build an int vector
std::sort(myvector.begin(), myvector.end());
std::vector<int>::iterator it;
//Use unique algorithm to get the unique values.
it = std::unique(myvector.begin(), myvector.end());
positions.resize(std::distance(myvector.begin(),it));
if (myvector.size() > 1) {
std::cout << "All elements are not the same!" << std::endl;
}
However reading on the internet and SO, I see other answers such using a set or the find_if algorithm. So what is the most efficient way of doing this and why? I imagine mine is not the best way since it involves sorting every element and then a resizing of the vector - but maybe I'm wrong.
You need not to use std::sort. It can be done in a simpler way:
if ( std::adjacent_find( myvector.begin(), myvector.end(), std::not_equal_to<>() ) == myvector.end() )
{
std::cout << "All elements are equal each other" << std::endl;
}
you can use std::equal
version 1:
//assuming v has at least 1 element
if ( std::equal(v.begin() + 1, v.end(), v.begin()) )
{
//all equal
}
This will compare each element with the previous one.
version 2:
//assuming v has at least 1 element
int e = v[0]; //preferably "const auto& e" instead
bool all_equal = true;
for(std::size_t i = 1,s = v.size();i<s && all_equal;i++)
all_equal = e == v[i];
Edit:
Regarding performance, after testing with 100m elements i found out that in Visual Studio 2015 version 1 is about twice as fast as version 2. This is because the latest compiler for vs2015 uses sse instructions in c++ std implementations when you use ints, float , etc..
if you use _mm_testc_si128 you will get a similar performance to std::equal
using std::all_of and C++11 lambda
if (all_of(values.begin(), values.end(), [&] (int i) {return i == values[0];})){
//all are the same
}
Given no constraints on the vector, you have to iterate through the vector at least once, no matter the approach. So just pick the first element and check that all others are equal to it.
While the asymptotic complexity of std::unique is linear, the actual cost of the operation is probably much larger than you need, and it is an inplace algorithm (it will modify the data as it goes).
The fastest approach is to assume that if the vector contains a single element, it is unique by definition. If the vector contains more elements, then you just need to check whether all of them are exactly equal to the first. For that you only need to find the first element that differs from the first, starting the search from the second. If there is such an element, the elements are not unique.
if (v.size() < 2) return true;
auto different = std::find_if(v.begin()+1, v.end(),
[&v](auto const &x) { x != v[0]; });
return different == v.end();
That is using C++14 syntax, in an C++11 toolchain you can use the correct type in the lambda. In C++03 you could use a combination of std::not, std::bind1st/std::bind2nd and std::equal in place of the lambda.
The cost of this approach is distance(start,different element) comparisons and no copies. Expected and worst case linear cost in the number of comparisons (and no copies!)
Sorting is an O(NlogN) task.
This is easily solvable in O(N), so your current method is poor.
A simple O(N) would be as Luchian Grigore suggests, iterate over the vector, just once, comparing every element to the first element.
if(std::all_of(myvector.begin()+1, myvector.end(), std::bind(std::equal_to<int>(),
std::placeholders::_1, myvector.front())) {
// all members are equal
}
You can use FunctionalPlus(https://github.com/Dobiasd/FunctionalPlus):
std::vector<std::string> things = {"same old", "same old"};
if (fplus::all_the_same(things))
std::cout << "All things being equal." << std::endl;
Maybe something like this. It traverses vector just once and does not mess with the vector content.
std::vector<int> values { 5, 5, 5, 4 };
bool equal = std::count_if(values.begin(), values.end(), [ &values ] (auto size) { return size == values[0]; }) == values.size();
If the values in the vector are something different than basic type you have to implement equality operator.
After taking into account underscore_d remarks, I'm changing possible solution
std::vector<int> values { 5, 5, 5, 4 };
bool equal = std::all_of(values.begin(),values.end(),[ &values ] (auto item) { return item == values[0]; });
In your specific case, iterating over vector element and finding a different element from the first one would be enough. You may even be lucky enough to stop before evaluating all the elements in your vector. (A while loop could be used but I sticked with a for loop for readability reasons)
bool uniqueElt = true;
int firstItem = *myvector.begin();
for (std::vector<int>::const_iterator it = myvector.begin()+1; it != myvector.end() ; ++it) {
if(*it != firstItem) {
uniqueElt = false;
break;
}
}
In case you want to know how many different values your vector contains, you could build a set and check its size to see how many different values are inside:
std::set mySet;
std::copy(mySet.begin(), myvector.begin(), myvector.end());
You can simply use std::count to count all the elements that match the starting element:
std::vector<int> numbers = { 5, 5, 5, 5, 5, 5, 5 };
if (std::count(std::begin(numbers), std::end(numbers), numbers.front()) == numbers.size())
{
std::cout << "Elements are all the same" << std::endl;
}
LLVM provides some independently usable headers+libraries:
#include <llvm/ADT/STLExtras.h>
if (llvm::is_splat(myvector))
std::cout << "All elements are the same!" << std::endl;
https://godbolt.org/z/fQX-jc
for the sake of completeness, because it still isn't the most efficient, you can use std::unique in a more efficient way to decide whether all members are the same, but beware that after using std::unique this way the container is useless:
#include <algorithm>
#include <iterator>
if (std::distance(cntnr.begin(), std::unique(cntnr.begin(), cntnr.end()) == 1)
{
// all members were the same, but
}
Another approach using C++ 14:
bool allEqual = accumulate(v.begin(), v.end(), true, [first = v[0]](bool acc, int b) {
return acc && (b == first);
});
which is also order N.
Here is a readable C++17 solution which might remind students of the other constructors of std::vector:
if (v==std::vector(v.size(),v[0])) {
// you guys are all the same
}
...before C++17, the std::vector rvalue would need its type provided explicitly:
if (v==std::vector<typename decltype(v)::value_type>(v.size(),v[0])) {
// you guys are all the same
}
The C++ function is defined in library in STL. This function operates on whole range of array elements and can save time to run a loop to check each elements one by one. It checks for a given property on every element and returns true when each element in range satisfies specified property, else returns false.
// C++ code to demonstrate working of all_of()
#include <vector>
#include <algorithm>
#include <iostream>
int main()
{
std::vector<int> v(10, 2);
// illustrate all_of
if (std::all_of(v.cbegin(), v.cend(), [](int i){ return i % 2 == 0; }))
{
std::cout << "All numbers are even\n";
}
}
If I have a vector of values and want to check that they are all the same, what is the best way to do this in C++ efficiently? If I were programming in some other language like R one way my minds jumps to is to return only the unique elements of the container and then if the length of the unique elements is more than 1, I know all the elements cannot be the same. In C++ this can be done like this:
//build an int vector
std::sort(myvector.begin(), myvector.end());
std::vector<int>::iterator it;
//Use unique algorithm to get the unique values.
it = std::unique(myvector.begin(), myvector.end());
positions.resize(std::distance(myvector.begin(),it));
if (myvector.size() > 1) {
std::cout << "All elements are not the same!" << std::endl;
}
However reading on the internet and SO, I see other answers such using a set or the find_if algorithm. So what is the most efficient way of doing this and why? I imagine mine is not the best way since it involves sorting every element and then a resizing of the vector - but maybe I'm wrong.
You need not to use std::sort. It can be done in a simpler way:
if ( std::adjacent_find( myvector.begin(), myvector.end(), std::not_equal_to<>() ) == myvector.end() )
{
std::cout << "All elements are equal each other" << std::endl;
}
you can use std::equal
version 1:
//assuming v has at least 1 element
if ( std::equal(v.begin() + 1, v.end(), v.begin()) )
{
//all equal
}
This will compare each element with the previous one.
version 2:
//assuming v has at least 1 element
int e = v[0]; //preferably "const auto& e" instead
bool all_equal = true;
for(std::size_t i = 1,s = v.size();i<s && all_equal;i++)
all_equal = e == v[i];
Edit:
Regarding performance, after testing with 100m elements i found out that in Visual Studio 2015 version 1 is about twice as fast as version 2. This is because the latest compiler for vs2015 uses sse instructions in c++ std implementations when you use ints, float , etc..
if you use _mm_testc_si128 you will get a similar performance to std::equal
using std::all_of and C++11 lambda
if (all_of(values.begin(), values.end(), [&] (int i) {return i == values[0];})){
//all are the same
}
Given no constraints on the vector, you have to iterate through the vector at least once, no matter the approach. So just pick the first element and check that all others are equal to it.
While the asymptotic complexity of std::unique is linear, the actual cost of the operation is probably much larger than you need, and it is an inplace algorithm (it will modify the data as it goes).
The fastest approach is to assume that if the vector contains a single element, it is unique by definition. If the vector contains more elements, then you just need to check whether all of them are exactly equal to the first. For that you only need to find the first element that differs from the first, starting the search from the second. If there is such an element, the elements are not unique.
if (v.size() < 2) return true;
auto different = std::find_if(v.begin()+1, v.end(),
[&v](auto const &x) { x != v[0]; });
return different == v.end();
That is using C++14 syntax, in an C++11 toolchain you can use the correct type in the lambda. In C++03 you could use a combination of std::not, std::bind1st/std::bind2nd and std::equal in place of the lambda.
The cost of this approach is distance(start,different element) comparisons and no copies. Expected and worst case linear cost in the number of comparisons (and no copies!)
Sorting is an O(NlogN) task.
This is easily solvable in O(N), so your current method is poor.
A simple O(N) would be as Luchian Grigore suggests, iterate over the vector, just once, comparing every element to the first element.
if(std::all_of(myvector.begin()+1, myvector.end(), std::bind(std::equal_to<int>(),
std::placeholders::_1, myvector.front())) {
// all members are equal
}
You can use FunctionalPlus(https://github.com/Dobiasd/FunctionalPlus):
std::vector<std::string> things = {"same old", "same old"};
if (fplus::all_the_same(things))
std::cout << "All things being equal." << std::endl;
Maybe something like this. It traverses vector just once and does not mess with the vector content.
std::vector<int> values { 5, 5, 5, 4 };
bool equal = std::count_if(values.begin(), values.end(), [ &values ] (auto size) { return size == values[0]; }) == values.size();
If the values in the vector are something different than basic type you have to implement equality operator.
After taking into account underscore_d remarks, I'm changing possible solution
std::vector<int> values { 5, 5, 5, 4 };
bool equal = std::all_of(values.begin(),values.end(),[ &values ] (auto item) { return item == values[0]; });
In your specific case, iterating over vector element and finding a different element from the first one would be enough. You may even be lucky enough to stop before evaluating all the elements in your vector. (A while loop could be used but I sticked with a for loop for readability reasons)
bool uniqueElt = true;
int firstItem = *myvector.begin();
for (std::vector<int>::const_iterator it = myvector.begin()+1; it != myvector.end() ; ++it) {
if(*it != firstItem) {
uniqueElt = false;
break;
}
}
In case you want to know how many different values your vector contains, you could build a set and check its size to see how many different values are inside:
std::set mySet;
std::copy(mySet.begin(), myvector.begin(), myvector.end());
You can simply use std::count to count all the elements that match the starting element:
std::vector<int> numbers = { 5, 5, 5, 5, 5, 5, 5 };
if (std::count(std::begin(numbers), std::end(numbers), numbers.front()) == numbers.size())
{
std::cout << "Elements are all the same" << std::endl;
}
LLVM provides some independently usable headers+libraries:
#include <llvm/ADT/STLExtras.h>
if (llvm::is_splat(myvector))
std::cout << "All elements are the same!" << std::endl;
https://godbolt.org/z/fQX-jc
for the sake of completeness, because it still isn't the most efficient, you can use std::unique in a more efficient way to decide whether all members are the same, but beware that after using std::unique this way the container is useless:
#include <algorithm>
#include <iterator>
if (std::distance(cntnr.begin(), std::unique(cntnr.begin(), cntnr.end()) == 1)
{
// all members were the same, but
}
Another approach using C++ 14:
bool allEqual = accumulate(v.begin(), v.end(), true, [first = v[0]](bool acc, int b) {
return acc && (b == first);
});
which is also order N.
Here is a readable C++17 solution which might remind students of the other constructors of std::vector:
if (v==std::vector(v.size(),v[0])) {
// you guys are all the same
}
...before C++17, the std::vector rvalue would need its type provided explicitly:
if (v==std::vector<typename decltype(v)::value_type>(v.size(),v[0])) {
// you guys are all the same
}
The C++ function is defined in library in STL. This function operates on whole range of array elements and can save time to run a loop to check each elements one by one. It checks for a given property on every element and returns true when each element in range satisfies specified property, else returns false.
// C++ code to demonstrate working of all_of()
#include <vector>
#include <algorithm>
#include <iostream>
int main()
{
std::vector<int> v(10, 2);
// illustrate all_of
if (std::all_of(v.cbegin(), v.cend(), [](int i){ return i % 2 == 0; }))
{
std::cout << "All numbers are even\n";
}
}
I am writing an octree algorithm.
Inside function I traverse octree.
I get node pointer and Sphere as input. I check if node should hold sphere then I want to add it
to nodes object list and remove it from its parents list. following is code
functionBody()
{
.....
if (!node->objectList.empty())
node->objectList.erase(std::remove_if(node->objectList.begin(), node->objectList.end()-1 , [&t](auto& temp) { return temp == t; }));
...
}
typedef struct Sphere
{
Sphere() = default;
Sphere(const Vector3 centre_, const float radius_, const Material& material_) : centre(centre_), radius(radius_), material(material_)
{
assert(radius != 0);
invRadius = 1.0 / radius;
Vector3 radiusOffset = Vector3(radius);
aabb.min = Vector3(centre - radiusOffset);
aabb.max = Vector3(centre + radiusOffset);
}
bool operator==(const Sphere& rhs)
{
return (centre == rhs.centre) && (radius == rhs.radius);
}
Vector3 centre;
float radius;
float invRadius;
Material material;
AABB aabb;
}Sphere;
As you can see for Sphere I have operator== defined.
I see that remove_if is removing element even when predicate is returning false.
for example, first iteration it finds one sphere t and removed it from parents vector using remove_if. This t was present at last of vector. consider now parent remains with 3 spheres in its vector but, when I go to other child now we still try to search t in parent and remove_if still removes last entry. I don't get why?
std::remove_if returns the end iterator provided when it doesn't find anything to remove. You've given node->objectList.end()-1 as the end iterator which is an iterator to the last element in node->objectList. This is what you pass to erase when you don't find t so the last element gets erased.
To fix the problem, use the overload of erase that takes a range of elements :
if (!node->objectList.empty())
{
auto end_iter = node->objectList.end();
auto to_remove = std::remove_if(
node->objectList.begin(), end_iter,
[&t](auto& temp) { return temp == t; });
node->objectList.erase(to_remove, end_iter);
}
Now if t isn't found erase won't do anything at all. In that case, remove_if returns end_iter and erase tried to erase the elements in the empty range defined by end_iter and itself.
I'm not sure why you were using node->objectList.end() - 1. I'm assuming it was either a mistake or a workaround for the crash that you would otherwise likely get with the previous code.
As you are calling the method erase that accepts only one iterator (not a range of iterators) and the algorithm std::remove_if is called with the second iterator of the range of container elements specified like
node->objectList.end()-1
then even if the element is not found in the container the algorithm remove_if will return the iterator node->objectList.end()-1 that points to a valid object in the container. This object will be erased from the container.
Here is a demonstrative program that reproduces the problem.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
std::vector<int> v = { 1, 3, 5, 7, 9 };
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
while ( v.size() > 1 )
{
v.erase( std::remove_if( std::begin( v ), std::prev( std::end( v ) ),
[]( const auto &item )
{
return item % 2 == 0;
} ) );
}
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
return 0;
}
Its output is
1 3 5 7 9
1
That is none element in the vector is an even number. Nevertheless all elements except one were erased from the vector.
It seems that you are incorrectly specifying the range. It should be specified like a pair
node->objectList.begin(), node->objectList.end()
Or before erasing an element you should check whether the returned iterator is equal to node->objectList.end() - 1 (provided that you indeed want to use the range shown in your question). In this case the method erase should not be called. Or you should specify an erased range of iterators like
if (!node->objectList.empty())
node->objectList.erase(std::remove_if(node->objectList.begin(), node->objectList.end()-1 , [&t](auto& temp) { return temp == t; }).
node->objectList.end()-1);
Again provided that you indeed want to use the second iterator of the range like node->objectList.end()-1 instead of node->objectList.end().
The problem is to find an integer without it's pair in a sequence of integers. Here's what I wrote so far, to me it looks like it should work but it doesn't. Any help for a noob programmer?
using namespace std;
int lonelyinteger(vector < int > a, int _a_size) {
for (int i = 0; i < _a_size; i++)
{
bool flag = false;
for (int n = i + 1; n < _a_size; n++)
{
if (a.at(i) == a.at(n))
{
flag = true;
break;
}
}
if (flag == false)
{
return a.at(i);
}
}
return 0;
}
For the input 1 1 2 it outputs 1 while it's supposed to 2
for 0 0 1 2 1 it outputs 0 and here it has to be 2
The problem is that your inner loop only checks from the index i and onward for a duplicate. In the case 1 1 2 the first loop encounters a[1] which is 1. After that index, there is no element that is equal to 1, so the function returns 1.
In general, there is a better solution to this problem. Instead of going through the vector twice, you can use a set to keep track of all the elements you have already encountered. For each element, check if the set already contains it. If not, add it to the set. Otherwise, remove it from the set. Anything remaining in the set will be unique within the vector.
All of the answers are good.
Now, assume that the array cannot be sorted, here is a somewhat lazy approach using std::map, but shows what can be done using the various algorithm functions.
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int lonelyinteger(const std::vector<int>& a)
{
typedef std::map<int, int> IntMap;
IntMap theMap;
// build the map
for_each(a.begin(), a.end(), [&](int n){ theMap[n]++; });
// find the first entry with a count of 1
return
find_if(theMap.begin(), theMap.end(),
[](const IntMap::value_type& pr){return pr.second == 1; })->first;
}
int main()
{
std::vector<int> TestVect = { 1, 1, 2 };
cout << lonelyinteger(TestVect);
}
Live example: http://ideone.com/0t89Ni
This code assumes that
the passed in vector is not empty,
the first item found with a count of 1 is the lonely value.
There is at least one "lonely value".
I also changed the signature to take a vector by reference and not send the count (since a vector knows its own size).
The code does not do any hand-coded loops, so that is one source of error removed.
Second, the count of the number of times a number is seen is more or less, done by the map using operator[] to insert new entries, and ++ to increase the count on the entry.
Last, the search for the first entry with only a count of 1 is done with std::find_if, again guaranteeing success (given that the data follows the assumptions made above).
So basically, without really trying hard, a solution can be written using algorithm functions and usage of the std::map associative container.
If your data will consist of multiple (or even no) "lonely" integers, the following changes can be made:
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
using namespace std;
std::vector<int> lonelyinteger(const std::vector<int>& a)
{
std::vector<int> retValue;
typedef std::map<int, int> IntMap;
IntMap theMap;
// build the map
for_each(a.begin(), a.end(), [&](int n){ theMap[n]++; });
// find all entries with a count of 1
for_each(theMap.begin(), theMap.end(),
[&](const IntMap::value_type& pr)
{if (pr.second == 1) retValue.push_back(pr.first); });
// return our answer
return retValue;
}
int main()
{
std::vector<int> TestVect = { 1, 1, 2, 3, 5, 0, 2, 8 };
std::vector<int> ans = lonelyinteger(TestVect);
copy(ans.begin(), ans.end(), ostream_iterator<int>(cout," "));
}
Live example: http://ideone.com/40NY4k
Note that we now retrieve any entries with an item of 1, and store it in a vector that will be returned.
Simple answer might be to just sort the lists and then look for something which has a different value before and after it..
Your problem is that the last item of any given value in the list has no subsequent duplicate values and you are thinking having no subsequent duplicates is the same as having no duplicates (which is false).
If you don't want to remove values your inner look has seen and earlier identified as a duplicate of a "previous" value loop over all values in the inner loop ignoring the match with itself.
I have a map with a struct as a value type
map<int id, struct_t*> table
struct_t
{
int prev;
int wt;
string name;
}
Using only prev, I need to find the corresponding id. Thanks so much in advance!
EDIT:
int key=0;
for(auto it = table.begin(); it != table.end(); ++it)
{
if(table[(*it).first].prev == ?)
}
This is how my map data looks like:
id prev abundance thing
1573 -1 0 book
1864 1573 39 beds
2075 1864 41 tray
1760 2075 46 cups
For each id, I need to find the NEXT matching id. So, for 1573 from the prev column I need to find a matching 'id' which is 1864. Also, std::next doesn't work because the data set can have the matching ids not necessarily in the next element.Hope this helps!
PLEASE PLEASE help me!!! MY boss is already disappointed that I'm taking so much time to learn C++ (its been 3 weeks already!)
If you've got a modern compiler (supports lambdas), you can do the following:
const int prevToFind = 10;
auto findResult = std::find_if(std::begin(table), std::end(table), [&](const std::pair<int, struct_t*> &pair)
{
return pair.second->prev == prevToFind;
});
int foundKey = 0; // You might want to initialise this to a value you know is invalid in your map
struct_t *foundValue = nullptr
if (findResult != std::end(table))
{
foundKey = findResult->first;
foundValue = findResult->second;
// Now do something with the key or value!
}
Let me know if you have an older compiler, and I can update the example to use a predicate class instead.
Simple loop can do it:
#include <map>
#include <string>
#include <iostream>
int main()
{
std::map<int, std::string> m = {
std::make_pair(0, "zero"), std::make_pair(1, "one"), std::make_pair(2, "two")
};
int key = 0;
for (auto &i : m) {
if (i.second == "two") {
key = i.first;
break; // to stop searching
}
}
std::cout << key << std::endl;
}
Of course you need to set up your own if-statement for searching.
Please note, boost bidirectional map could be a solution (boost::bimap)
Looping over the map of course does the trick, but you may want to consider using a second map as an index:
map<int,int> table_idx;
Whenever you add new entries to table you will need to update table_idx as well, storing the id that corresponds to every prev. table_idx will then allow you to reverse-lookup the id in log(N) time:
int prev_for_id = table_idx[id];
Im getting a feeling that you are a beginner so it would be nice if you would tell us what are you trying to do because maybe you are trying to solve a wrong problem.
Like noted maps are designed to be searched by the key, not value.
That being said if you insist on searching the map this way you will problably wanna check out Boost Bimap.
Is it not possible to generate a reverse map with something like that:
typedef std::map<int, struct_t*> map_t;
typedef std::map<struct_t*, int> reverse_map_t;
reverse_map_t get_reverse( map_t m )
{
reverse_map_t r;
for( const auto& p: m )
{
r[p.second] = p.first;
}
return r;
}