I've got a list of elements, say, integers and I want to check if my variable (another integer) is one of the elements from the list. In python I'd do:
my_list = [1,2,3,4] # elements
my_var = 3 # my variable
my_var in my_list # returns boolean
How to do that in C++? I thought of using std::list, but I can find no find method in it. I can see such method in std::set structure.
More deeply, the problem is that my program is given some unique ids (a list, a set, whatever) and I iterate over a long list of input data (ids) and check if they are included in the list (boolean value returned for each iteration step). And I'm not sure how should I do that in C++.
You can use std::find
bool found = (std::find(my_list.begin(), my_list.end(), my_var) != my_list.end());
You need to include <algorithm>. It should work on standard containers, vectors lists, etc...
std::list does not provide a search method. You can iterate over the list and check if the element exists or use std::find. But I think for your situation std::set is more preferable. The former will take O(n) time but later will take O(lg(n)) time to search.
You can simply use:
int my_var = 3;
std::set<int> mySet {1, 2, 3, 4};
if(mySet.find(myVar) != mySet.end()){
//do whatever
}
you must #include <algorithm>, then you can use std::find
They really should add a wrapper. Like this:
namespace std
{
template<class _container,
class _Ty> inline
bool contains(_container _C, const _Ty& _Val)
{return std::find(_C.begin(), _C.end(), _Val) != _C.end(); }
};
...
if( std::contains(my_container, what_to_find) )
{
}
A one-liner solution, similar to python, would be (std::set<int> {1, 2, 3, 4}).count(my_var) > 0.
Minimal working example
int my_var = 3;
bool myVarIn = (std::set<int> {1, 2, 3, 4}).count(my_var) > 0;
std::cout << std::boolalpha << myVarIn << std::endl;
prints true or false dependent of the value of my_var.
Use std::find, something like:
if (std::find(std::begin(my_list), std::end(my_list), my_var) != std::end(my_list))
// my_list has my_var
Declare additional helper function like this:
template <class T, class I >
bool vectorContains(const vector<T>& v, I& t)
{
bool found = (std::find(v.begin(), v.end(), t) != v.end());
return found;
}
And use it like this:
void Project::AddPlatform(const char* platform)
{
if (!vectorContains(platforms, platform))
platforms.push_back(platform);
}
Snapshot of example can be found here:
https://github.com/tapika/cppscriptcore/blob/b7f3d62747494a52a440482e841ffb016a3fc56e/SolutionProjectModel/Project.cpp#L13
Since C++20 you can use l.contains(my_var)
https://www.modernescpp.com/index.php/more-convenience-functions-for-containers-with-c-20
Related
I have an std::map and an std::unordered_set with the same key.
I want to remove all keys from the set that do not exist in the map.
My idea was to do something like the following:
#include <map>
#include <unordered_set>
int main()
{
std::map<uint64_t, std::string> myMap = {
{1, "foo"},
{2, "bar"},
{3, "morefoo"},
{4, "morebar"}
};
std::unordered_set<uint64_t> mySet = { 1, 2, 3, 4, 123 };
for (const auto key : mySet)
{
const auto mapIterator = myMap.find(key);
if (myMap.end() == mapIterator)
mySet.erase(key);
}
return 0;
}
And then invoke it on a timer callback every few seconds, however, the snippet above throws an assert when trying to delete the key 123 from mySet, stating:
List iterator is not incrementable.
The thing is, even if it didn't throw an exception I feel like this idea is far from elegant/optimal. I'm wondering if there is a better way to approach this problem?
Thanks.
As stated in answers to this question How to remove from a map while iterating it? you cannot erase elements in container while iterating over it in a for range loop, so your code should use iterator. As such answer already provided I would not duplicate it.
For efficiency you have a quite wrong approach - you are doing lookup in std::map while iterating std::unordered_set, which should be opposite as std::unorederd_set provides faster lookup time (otherwise there is not point for you use it instead of std::set). One of possible approach is to create a copy:
auto copySet = mySet;
for( const auto &p : myMap )
copySet.erase( p.first );
for( const auto v : copySet )
mySet.erase( v );
which could be more efficient, but that depends on your data. Better approach to choose proper data types for your containers.
Note: by wrong approach I mean efficiency only for this particular situation presented in your question, but this seem to be a part of a larger program and this solution can be right for it as there could be more important cases when this data structure works well.
As stated in the comments
for (const auto key : mySet)
{
const auto mapIterator = myMap.find(key);
if (myMap.end() == mapIterator)
mySet.erase(key);
}
will have undefined behavior. When you erase element 123 from mySet you invalidate the iterator that the range based for loop is using. incrementing that iterator is not allowed after you do that. What you can do is switch to a regular for loop so you can control when the iterator is incremented like
for (auto it = mySet.begin(); it != mySet.end();)
{
if (myMap.find(*it) == myMap.end())
it = mySet.erase(it);
else
++it;
}
and now you always have a valid iterator as erase will return the next valid iterator.
I have a vector of std::unique_ptr<Foo> objects. I want to get a collection of all vector items that match some condition.
I see the std functions but they all seem to test for a predicate (and return bool) or return a single element.
Is there a built-in mechanism to get a collection that's a subset of a vector? If not, is there a way to construct an iterator that tests items against an arbitrary predicate (to identify ones that meet my condition) and a mechanism to return all items that meet that predicate?
Be warned, since you've got a vector of unique_ptr, those elements can only be moved around, i.e. once you have got the subset, the original vector will not be the same anymore.
The least destructive method is to use std::stable_partition to divide the vector into two groups, while keeping everything in the same vector:
auto sep = std::stable_partition(vec.begin(), vec.end(), [](const auto& foo) {
return foo->is_good();
});
// the part `vec.begin() .. sep` contains all "good" foos.
// the part `sep .. vec.end()` contains all "bad" foos.
If order is not important, use std::partition instead. The usage is the same.
If you want to split the bad foos into another vector, you could use std::copy_if + std::make_move_iterator to move the objects out. Note that this will leave holes everywhere. Use std::remove to clean them up.
decltype(vec) bad_vec;
std::copy_if(std::make_move_iterator(vec.begin()),
std::make_move_iterator(vec.end()),
std::back_inserter(bad_vec),
[](const auto& p) { return !p->is_good(); });
auto new_end = std::remove(vec.begin(), vec.end(), nullptr);
vec.erase(new_end, vec.end());
If you no longer care about the "bad" objects, use std::remove_if:
auto new_end = std::remove_if(vec.begin(), vec.end(), [](const auto& foo) {
return !foo->is_good();
});
vec.erase(new_end, vec.end());
// now `vec` only contains "good" foos.
If you just want to get the raw pointers, instead of the unique_ptr itself, you could use std::transform to fill up a vector<Foo*> and then remove_if to filter it... But at this point it is probably just easier to write the for loop.
std::vector<int*> good_vec;
for (const auto& foo : vec) {
if (foo->is_good()) {
good_vec.push_back(foo.get());
}
}
Since your vector holds unique_ptr's (which we don't make copies of) - I'd recommend the second option you inquired about: An iterator which only iterates those elements matching your predicate. This is exactly boost::filter_iterator.
Sort-of-an example:
bool points_to_positive(int* ptr) {
return ptr != nullptr and *ptr > 0;
}
// ...
std::vector<std::unique_ptr<int>> vec;
// ...
auto iterator = boost::make_filter_iterator(
&points_to_positive, std::begin(vec), std::end(vec)
);
if, however, you plan on making that iteration multiple times, and do not want to trade time for space, you would probably be better served by just copying out the actual pointers like in #kennytm's last suggested option.
What you asked for is std::copy_if from <algorithm>. For unique_ptr elements, which cannot be copied, this is not what you want. Sample code:
#include <algorithm>
#include <array>
#include <cstdlib>
#include <experimental/array>
#include <iostream>
#include <type_traits>
#include <vector>
using std::cout;
using std::endl;
using std::size_t;
bool is_even( const int n )
{
// True iff n is even.
return n % 2 == 0;
}
std::ostream& operator<< ( std::ostream& os, const std::vector<int>& container )
{
// Boilerplate instrumentation.
for ( const int& x : container )
os << x << ' ';
return os;
}
int main(void)
{
// Our input array, raw:
constexpr int digits[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// The number of input elements:
constexpr size_t ndigits = std::extent<decltype(digits)>();
// Container wrapping our input array:
constexpr std::array<int, ndigits > numbers =
std::experimental::to_array(digits);
std::vector<int> even_numbers;
even_numbers.reserve(ndigits); // Upper bound on output size.
std::copy_if( numbers.cbegin(),
numbers.cend(),
std::back_inserter(even_numbers),
is_even );
even_numbers.shrink_to_fit();
// Correct output is "2 4 6 8 "
cout << even_numbers << endl;
return EXIT_SUCCESS;
}
However, your array contains unique_ptr objects, which can’t be copied. Several answers have other good suggestions to get equivalent results. If you want to copy the references meeting the requirements to a different collection, though, you could also change unique_ptr to shared_ptr or weak_ptr, which can be copied.
I have a vector of structs which have about 100 members within the struct. The vector itself can grow to be as large as 1000 elements. I am trying to find a simple way to search the list based on a set of 3 elements every struct contains amongst its many members:
std::string firstName;
std::string lastName;
size_t age;
I'm trying to find a way to search the vector based on a key derived from these three values, rather than iterating through the list and doing something like:
for ( int i = 0; i < list.length(); i++ )
{
if (element[i].lastName == lastNameToFind &&
element[i].firstName == firstNameToFind &&
element[i].age == ageToFind)
{
// found the element
}
}
I am looking for faster methods that take advantage of the underlying logic in std::vector to operate more efficiently, and if I want to search by different key tuples, I just change a couple lines of code rather than writing another search function. Is such an approach possible?
You could use std::find_if and provide a lambda as a predicate. It will be simpler and more flexible but I'm not sure it will necessarily be faster.
auto findByNameAndAge = [&lastNameToFind, &firstNameToFind, &ageToFind]
(const MyStruct& s) {
return s.lastName == lastNameToFind &&
s.firstName == firstNameToFind &&
s.age == ageToFind;
};
auto result = std::find_if(list.begin(), list.end(), findByNameAndAge);
Live demo.
Alternatively, you could create a comparison operator with a key tuple or struct
using MyKey = std::tuple<std::string, std::string, int>;
bool operator==(const MyStruct& s, const MyKey& key){
return std::tie(s.lastName, s.firstName, s.age) == key;
}
and use std::find:
auto key = MyKey{"Smith", "John", 10};
auto result = std::find(list.begin(), list.end(), key);
Live demo.
If you want faster search you might need to reconsider how you are storing the structs. Perhaps maintain indexes or keep the vector sorted but this may impact the performance of insertions.
The first off, why put it in a vector? I believe an urordered_map might be better off with the hash:
[&last_name, &first_name, age]()
{
return std::hash<std::string>(last_name+","+first_name) ^ age;
};
I think ^ is a good way of merging two hashes into one. Maybe google that part?
If you insist on a vector, maybe make a smart_ptr and store that in your vector then an unordered_map with the smart_ptr as a value.
PS:
OK xor is a crappy way to hash. use boost::hash_combine or this answer.
Suppose you are given a vector of 2D points and are expected to find the point with the least Euclidean norm.
The points are provided as std::vector<point_t> points whith the following typedef std::pair<double, double> point_t. The norm can be calculated using
double norm(point_t p)
{
return pow(p.first, 2) + pow(p.second, 2);
}
Writing the loop myself I would do the following:
auto leastPoint = points.cend();
auto leastNorm = std::numeric_limits<double>::max();
for (auto iter = points.cbegin(), end = points.cend(); iter != end; ++iter)
{
double const currentNorm = norm(*iter);
if (currentNorm < leastNorm)
{
leastNorm = currentNorm;
leastPoint = iter;
}
}
But one should use STL algorithms instead of wirting one's own loops, so I'm tempted to to the following:
auto const leastPoint = std::min_element(points.cbegin(), points.cend(),
[](point_t const lhs, point_t const rhs){ return norm(lhs) < norm(rhs); });
But there is a caveat: if n = points.size() then the first implementation needs n evaluations of norm(), but the second implementation needs 2n-2 evaluations. (at least if this possible implementation is used)
So my question is if there exists any STL algorithm with which I can find that point but with only n evaluations of norm()?
Notes:
I am aware that big-Oh complexity is the same, but still the latter will lead to twice as many evaluations
Creating a separate vector and populating it with the distances seems a bit overkill just to enable the usage of an STL algorithm - different opinions on that?
edit: I actually need an iterator to that vector element to erase that point.
You could use std::accumulate (in the algorithm header):
Accumulate receive:
range
initial value
binary operator (optional, if not passed, operator+ would be called)
The initial value and every element of the range would be feed into the operator, the operator would return a result of the type of the initial value that would be feed into the next call to operator with the next element of the range and so on.
Example Code (Tested GCC 4.9.0 with C++11):
#include <algorithm>
#include <iostream>
#include <vector>
#include <cmath>
typedef std::pair<double, double> point_t;
struct norm_t {
point_t p;
double norm;
};
double norm(const point_t& p) {
return std::pow(p.first, 2) + std::pow(p.second, 2);
}
norm_t min_norm(const norm_t& x, const point_t& y) {
double ny = norm(y);
if (ny < x.norm)
return {y, ny};
return x;
}
int main() {
std::vector<point_t> v{{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}};
norm_t first_norm{v[0], norm(v[0])};
auto min_norm_point =
std::accumulate(v.begin(), v.end(), first_norm, min_norm);
std::cout << "(" << min_norm_point.p.first << "," << min_norm_point.p.second
<< "): " << min_norm_point.norm << '\n';
}
You could cache the minimum norm in the functor for avoid extra calculation (be aware: I'm using info about the implementation of std::min_element). The second element is the smallest found and the first is the iteration element.
struct minimum_norm {
minimum_norm() : cached_norm(-1) {}
bool operator()(const point_t& first, const point_t& second) {
if (cached_norm == -1)
cached_norm = norm(second);
double norm_first = norm(first);
if (norm_first < cached_norm) {
cached_norm = norm_first;
return true;
}
return false;
}
private:
double cached_norm;
};
int main()
{
std::vector<point_t> v{{3, 4}, {5, 6}, {1, 2}, {7, 8}, {9, 10}};
auto result = std::min_element(std::begin(v), std::end(v), minimum_norm());
std::cout << "min element at: " << std::distance(std::begin(v), result) << std::endl;
}
This is the sort of problem that boost::transform_iterator from the boost iterator library is designed to solve. There are limitations with the decorated iterator approach however and the C++ standards committee Ranges working group is looking into adding ranges to the standard which would potentially allow for a more functional approach of piping e.g. a transform to a min_element without needing temporary storage.
Eric Niebler has some interesting posts on ranges at his blog.
Unfortunately transform_iterator doesn't quite solve your problem given the way min_element is typically implemented - both iterators are dereferenced for each comparison so your function will still end up getting called more often than necessary. You could use the boost iterator_adaptor to implement something like a 'caching_transform_iterator' which avoids recomputing on each dereference but it would probably be overkill for something like norm(). It might be a useful technique if you had a more expensive computation though.
EDIT: Nevermind this, I misread the question.
I think you are mistaken in your assumption that min_element will perform 2N-2 comparisons
Per the c++ reference of min_element you can see that the algorithm performs essentially N comparison, which is the minimum for an unsorted array.
Here is a copy for the (very) unlikely case that www.cplusplus.com ever fails.
template <class ForwardIterator>
ForwardIterator min_element ( ForwardIterator first, ForwardIterator last )
{
if (first==last) return last;
ForwardIterator smallest = first;
while (++first!=last)
if (*first<*smallest) // or: if (comp(*first,*smallest)) for version (2)
smallest=first;
return smallest;
}
I have a Visual Studio 2008 C++03 application where I have two standard containers. I would like to remove from one container all of the items that are present in the other container (the intersection of the sets).
something like this:
std::vector< int > items = /* 1, 2, 3, 4, 5, 6, 7 */;
std::set< int > items_to_remove = /* 2, 4, 5*/;
std::some_algorithm( items.begin, items.end(), items_to_remove.begin(), items_to_remove.end() );
assert( items == /* 1, 3, 6, 7 */ )
Is there an existing algorithm or pattern that will do this or do I need to roll my own?
Thanks
Try with:
items.erase(
std::remove_if(
items.begin(), items.end()
, std::bind1st(
std::mem_fun( &std::set< int >::count )
, items_to_remove
)
)
, items.end()
);
std::remove(_if) doesn't actually remove anything, since it works with iterators and not containers. What it does is reorder the elements to be removed at the end of the range, and returns an iterator to the new end of the container. You then call erase to actually remove from the container all of the elements past the new end.
Update: If I recall correctly, binding to a member function of a component of the standard library is not standard C++, as implementations are allowed to add default parameters to the function. You'd be safer by creating your own function or function-object predicate that checks whether the element is contained in the set of items to remove.
Personally, I prefer to create small helpers for this (that I reuse heavily).
template <typename Container>
class InPredicate {
public:
InPredicate(Container const& c): _c(c) {}
template <typename U>
bool operator()(U const& u) {
return std::find(_c.begin(), _c.end(), u) != _c.end();
}
private:
Container const& _c;
};
// Typical builder for automatic type deduction
template <typename Container>
InPredicate<Container> in(Container const& c) {
return InPredicate<Container>(c);
}
This also helps to have a true erase_if algorithm
template <typename Container, typename Predicate>
void erase_if(Container& c, Predicate p) {
c.erase(std::remove_if(c.begin(), c.end(), p), c.end());
}
And then:
erase_if(items, in(items_to_remove));
which is pretty readable :)
One more solution:
There is standard provided algorithm set_difference which can be used for this.
But it requires extra container to hold the result. I personally prefer to do it in-place.
std::vector< int > items;
//say items = [1,2,3,4,5,6,7,8,9]
std::set<int>items_to_remove;
//say items_to_remove = <2,4,5>
std::vector<int>result(items.size()); //as this algorithm uses output
//iterator not inserter iterator for result.
std::vector<int>::iterator new_end = std::set_difference(items.begin(),
items.end(),items_to_remove.begin(),items_to_remove.end(),result.begin());
result.erase(new_end,result.end()); // to erase unwanted elements at the
// end.
You can use std::erase in combination with std::remove for this. There is a C++ idiom called the Erase - Remove idiom, which is going to help you accomplish this.
Assuming you have two sets, A and B, and you want to remove from B, the intersection, I, of (A,B) such that I = A^B, your final results will be:
A (left intact)
B' = B-I
Full theory:
http://math.comsci.us/sets/difference.html
This is quite simple.
Create and populate A and B
Create a third intermediate vector, I
Copy the contents of B into I
For each element a_j of A, which contains j elements, search I for the element a_j; If the element is found in I, remove it
Finally, the code to remove an individual element can be found here:
How do I remove an item from a stl vector with a certain value?
And the code to search for an item is here:
How to find if an item is present in a std::vector?
Good luck!
Here's a more "hands-on" in-place method that doesn't require fancy functions nor do the vectors need to be sorted:
#include <vector>
template <class TYPE>
void remove_intersection(std::vector<TYPE> &items, const std::vector<TYPE> &items_to_remove)
{
for (int i = 0; i < (int)items_to_remove.size(); i++) {
for (int j = 0; j < (int)items.size(); j++) {
if (items_to_remove[i] == items[j]) {
items.erase(items.begin() + j);
j--;//Roll back the iterator to prevent skipping over
}
}
}
}
If you know that the multiplicity in each set is 1 (not a multiset), then you can actually replace the j--; line with a break; for better performance.