I have a class that uses custom logic to generate some sequence:
class Example{
size_t FirstElement();
size_t NextElement(size_t currentelement);
//When element equals magic number this is
//signalling that the sequence is over.
static size_t MagicNumber =-1;
}
I could consume the sequence as follows:
Example example{};
for(size_t curelement = example.FirstElement;
curelement != Example::MagicNumber;
curelement = example.NextElement(currentelement))
{
//do something with the curelement
}
I would like a solution which makes it similarly easy to consume the sequence, but:
Avoiding the use of the magic number external to Example (i.e. while consuming).
That does not store the currentelement inside the `example' object.
That has perhaps a bit cleaner consumtion code in general?
That does not give substantial performance penalties compared to this code.
EDIT: Example should not return the whole sequence in one go, i.e. as std::vector.
Is there a good alternative. (Based on my (very limited) understanding of iterators, they should be the goto solution here? If so, how to implement such a solution?)
Yes, I would advise you to use iterators. They usually work the same way, like your code:
Example e;
for(auto it = e.begin(); it != e.end(); ++it)
{...}
//Can be simplified to
for(const auto &x : e)
{...}
where begin() will return the iterator pointing to the first element (like Example::FirstElement(). and end() the iterator to the element after the last (This could return your magic number). However...both values should be wrapped in a class and you should not just return integers as iterators.
For further reading I would suggest this and this post.
A for-loop is fine for iterating your class. You just seem to want it to be generic in how it terminates and presumably what the body does. Seems like overkill but this is a solution.
void Consume(Example &example, std::function<bool(Example)> terminateFunc, std::function<void(Example)> bodyFunc)
{
for(size_t curelement = example.FirstElement; !terminateFunc(curelement); curelement = example.NextElement(curelement))
{
bodyFunc(curelement);
}
}
i.e. terminateFunc and bodyFunc are passed in, and can be custom for whatever conditions you require.
auto condition = [](Example e) { return true; /* check if e satisfies some condition; */ };
auto body = [](Example e) { /* do something with e */ };
Consume(example, condition, body);
Related
I'm using C++20.
I have an object MyObject that contains a variable std::set<std::set<int>> nestedSet. I need to iterate through nestedSet and remove from the second-level sets an element that matches a search criteria. So far, I've tried the implementations:
void MyObject::removeFromNestedSet(int criteria) {
for(auto s : nestedSet){
std::erase_if(s, [&criteria](int i){return i == criteria;});
}
}
and
void MyObject::removeFromNestedSet(int criteria) {
for(auto s : nestedSet){
auto it = s.find(criteria);
if(it != s.end()){
s.erase(it, s.end());
}
}
}
Viewing the code progression with a debugger, I can see that within the frame of the removeFromNestedSet function, the element in the set matching the criteria IS removed. However, this removal is not reflected when observing the this->nestedSet object.
I haven't worked with C++ in a few years, but I suspect this is an issue with needing the range-based loop to point to the actual nested sets within nestedSet rather than a copy of the nested set?
You are having difficulty because a std::set's elements are always const.
This is because a std::set's elements are always ordered by their values. Changing a value could violate the order.
You must remove each element from your outer std::set before you can modify it.
void MyObject::removeFromNestedSet(int criteria) {
std::set<std::set<int>> newNestedSet;
while ( ! nestedSet.empty() ) {
// Remove an inner set, so it can be modified
auto setNode = nestedSet.extract( nestedSet.begin() );
// Modify the set
std::erase_if(setNode.value(), [&](int i){return i == criteria;});
// Place the result in a new set
newNestedSet.insert(std::move(setNode));
}
nestedSet = std::move(newNestedSet);
}
This solution doesn't make any copies of your data and preserves the integrity of any pointers or references to your stored ints.
Note that your sets may be in a different order after your modification.
Several options.
If you insist on that particular data-structure, you'll have to copy the entire thing over to a new set and then swap/move that with/into the member.
std::set<std::set<int>> dest;
for (auto const& n: nestedSet) {
std::set<int> ndest;
for (int i: n) {
if (i != criteria) {
ndest.insert(i);
}
}
dest.emplace(std::move(ndest));
}
nestedSet = std::move(dest);
Needless to say, this is terrible.
But maybe you don't really need to be dealing with a set to begin with. Often a vector is the better choice: std::vector<std::set<int>> nestedSet; (maybe even the inner set can be a vector!).
Then you do the algorithm like you tried:
for(auto& s : nestedSet) {
// ^--------- important, or you would be modifying a copy
std::erase_if(s, [&criteria](int i){return i == criteria;});
}
If you absolutely need a set, you could have an std::set<std::unique_ptr<std::set<int>>> nestedSet
for(auto const& p : nestedSet) {
// p is an std::unique_ptr<std::set<int>> const&
std::erase_if(*p, [&criteria](int i){return i == criteria;});
}
Of course this does introduce yet another layer of indirection, but with two nested sets this almost doesn't matter anymore.
I have a function that search a vector and returns the item if it is found. But I want to know that best software appraoch to handle if it is not found.
I have created a function and could return -1 or something but that wouldn't match the return type.
koalaGraph::PVertex Koala::lookUpVertexbyName(const std::string&vertexName, const std::vector<koalaGraph::PVertex>& koalaVertices) {
for (size_t i = 0; i < koalaVertices.size(); i++) {
if(koalaVertices[i]->info.name == vertexName)
return koalaVertices[i];
}
}
If a situation is encountered where the item being searched for is not in the vector then program will exit.
You can use std::optional
#include <optional>
std::optional<koalaGraph::PVertex>
Koala::lookUpVertexbyName(const std::string&vertexName,
const std::vector<koalaGraph::PVertex>& koalaVertices) {
for (size_t i = 0; i < koalaVertices.size(); i++) {
if(koalaVertices[i]->info.name == vertexName)
return koalaVertices[i];
}
return {};
}
int main()
{
Koala k;
//...
auto maybeVertex = k.lookUpVertexByName("foo",vertices);
if(maybeVertex)
koalaGraph::PVertex&& vertex = *maybeVertex;
//alternatively
if(maybeVertex.has_value())
//found
}
You could use a for-loop and return a iterator.
std::vector<koalaGraph::PVertex>::const_iterator
Koala::lookUpVertexbyName(
const std::string&vertexName,
const std::vector<koalaGraph::PVertex>& koalaVertices)
{
for(auto iter = koalaVertices.begin(); iter != koalaVertices.end(); ++iter) {
if(koalaVertices[i]->info.name == vertexName) {
return iter;
}
}
return koalaVertices.end();
}
Further you check if you got end back. end indicates if the value was found or not.
auto iter = <fucntioncall> // lookUpVertexbyName
if (iter == <vector>.end() {
// abort or do what ever you want
}
To use the value you have to dereference the iterator. DON'T derefence the end-iterator, it will lead you to neverland -> undefined behavior.
std::string test = *iter;
Why not use std::find_if instead of reinventing the wheel. See this link.
struct equal
{
equal(const std::string& vertexName) : vertexName_(vertexName) { }
bool operator()(const koalaGraph::PVertex& pVertex) const
{
return pVertex->info.name == vertexName_;
}
private:
std::string vertexName_;
};
And then:
std::find_if(koalaVertices.begin(), koalaVertices.end(), eq(vertexName));
Regarding handling the errors in function as it has already been stated there are multiple approaches that one can take. Returning an iterator instead of object(you will avoid copying this way too) is one of them. end() iterator would then indicate that the name was not found.
There are three ways to exit a function:
Return a value
Throw a value
Call std::abort or std::exit (possibly indirectly)
(std::longjmp which you shouldn't use)
If you don't do any of the above, then behaviour will be undefined. If you don't want to do 1., then your options are 2. or 3. Abort and exit will terminate the process. A throw can be caught, but an uncaught throw will cause std::abort.
Note that just because you don't find a value, it's not necessarily impossible to return some value. What you can do is return a "sentinel" value that represents "not found". For example, std::string functions that return an index will return std::string::npos when there is no result. Functions returning a pointer might return null, and functions returning an iterator would return an iterator the the end of the range.
If there is no representation of your return type that could be reserved for a sentinel, there is a way to add such representation by wrapping the return type with additional state. The standard library has a generic wrapper for this: std::optional.
Another wrapper is the proposed std::expected (it's not accepted to the standard as far as I know, but there are plenty of non-standard implementations). It allows storing information about the reason for not returning a proper value which similar to what you can do with exceptions.
P.S. Your function appears to be nearly identical to std::find_if. Use standard algorithms when possible. Also consider a data structure that is more efficient for searching if the search space is large.
I am currently struggling coming up with an optimized method for dynamic ordering. I currently have a vector that looks like this in some place of my code
std::vector<std::string> vec {
"optionB",
"optionA",
"optionC"
};
The items in the above vector can be shuffled.The items in this vector are inserted in a specific order so the above order can be different. For simplicity sakes I added the items during declaration.There are about 9 items in the actual case for simplicity I am using only 3 string items.
Now somewhere else in my code I have something like this.
void filter()
{
bool _optionA,_optionB,_optionC
...
//These boolean variables get assigned values
...
...
/*
Todo : I would like to change the ordering of the
following code based on the ordering of items in the
vector. Currently its in the order _optionA _optionB,
_optionC. I would like this ordering to be based
on the order of the strings as in the above vector.
so it should be _optionB,_optionA,_optionC ,
I understand the items in the vector are string
and the following are boolean types
*/
if(_optionA){
}
if(_optionB) {
}
if(_optionC){
}
}
The simplest approach that comes to my mind is
for(auto str : vec)
{
if( (str=="optionA" && _optionA))
{
//This was optionA
}
else if( (str=="optionB" && _optionB)) {
}
else if( (str=="optionC" && _optionC)) {
}
}
I want to know what would be the most optimized way to accomplish the above task ? I am looking for a solution that would avoid iterating through a vector since its in a performance centric piece of code. Is there a way for me to use integrate bitwise operations or something like array indexing to accomplish this task ? Please let me know if something is unclear
It sounds like you want map a string to an actual process. Could you create an interface option class and have instances of options mapped to the string that should cause them to occur? That way you could use the string as a key to get back an Option object and call something like myOption.execute().
The downside to this method is that you need to create a new option class and have it inherit from the interface each time you need a new option.
#Edit: Sorry I think I may have misunderstood the question. But I think the premise still applies you could have a map of string to boolean and just use the string as a key to get back whether the option is toggled on or off.
Assuming you load the vector in on start up, you can sort it at that point to your liking. For example, in alphabetical order. This will mean that you know the order of the vector therefore you can simply reference the vector by index when checking in the your filter function.
Load in data into vector std::vector<string> data = {"optionA", "optionB"};.
Sort using std::sort(data.begin, data.end); or any other sort method of your choice.
Then in you filter function check the vector based on index. if (data.at(1) == "optionA") { }
If I understand your problem correctly, you need to imply order_by on the boolean variables/predicates.
In the below program I will refer your (_optionA, _optionB, _optionC) as predicates even though they are bool, since we can upgrade this problem to work with predicates as well.
Based on the above assumption, I am going ahead with an implementation.
You should pass an ordered_predicates to your filter function.
ordered_predicates is sorted according to your desired criteria.
filter()'s job is just to execute them in the order defined.
auto filter(std::vector<bool> const & ordered_predicates)
-> void
{
for (auto const & condition : ordered_predicates) {
if (condition) {
// ... do your usual stuff here
}
}
}
So how should we go ahead to achieve this ordered_predicates?
We will create a function called order_by that will take an order_by_criteria and a mapping, which will help it in creating ordered_predicates.
With this function, creating ordered_predicates is just a one time cost.
auto order_by(std::vector<std::string> const & order_by_criteria,
std::map<std::string, bool> const & mapping)
-> std::vector<bool>
{
std::vector<bool> ordered_predicates;
for (auto const & item : order_by_criteria)
ordered_predicates.push_back(mapping.at(item));
return ordered_predicates;
}
Where order_by_criteria is your std::vector<std::string> and mapping is just a map which tells which string and predicates are associated.
std::vector<std::string> order_by_criteria { "optionB", "optionA", "optionC" };
std::map<std::string, bool> mapping = { {"optionA", _optionA },
{"optionB", _optionB },
{"optionC", _optionC } };
Here is a complete working program for your reference.
#include <iostream>
#include <map>
#include <vector>
auto order_by(std::vector<std::string> const & order_by_criteria,
std::map<std::string, bool> const & mapping)
-> std::vector<bool>
{
std::vector<bool> ordered_predicates;
for (auto const & item : order_by_criteria)
ordered_predicates.push_back(mapping.at(item));
return ordered_predicates;
}
auto filter(std::vector<bool> const & ordered_predicates)
-> void
{
for (auto const & condition : ordered_predicates) {
if (condition) {
// ... do your usual stuff here
}
}
}
int main()
{
bool _optionA = true, _optionB = false, _optionC = true;
std::vector<std::string> order_by_criteria { "optionB", "optionA", "optionC" };
std::map<std::string, bool> mapping = { {"optionA", _optionA },
{"optionB", _optionB },
{"optionC", _optionC } };
auto ordered_predicates = order_by(order_by_criteria, mapping);
filter(ordered_predicates);
filter(ordered_predicates); // call as many times as you want, with pre-decided order
return 0;
}
If I got the problem correctly, sorting is a way to go. Just sort the vector together with bool flags, using std::vector values as keys, and then simply check bool flags in fixed, lexicographic, order.
Suppose we have a vector {"optB", "optC", "optA"}. After sorting, the indices {0, 1, 2} will rearrange: std::size_t perm[] = {2, 0, 1}. Using this information, that can be precomputed (outside filter(...)), we can rearrange the bool flags:
bool options[N];
// populate options...
bool new_options[N];
for (std::size_t i = 0; i < N; ++i)
new_options[perm[i]] = options[i];
Now we simply check new_options successively:
if (new_options[0]) {
...
}
if (new_options[1]) {
...
}
To precompute perm array use std::map:
std::map<std::string, std::size_t> map;
for (std::size_t i = 0; i < N; ++i)
map.emplace(vec[i], i);
std::size_t perm[N];
auto m = map.begin();
for (std::size_t i = 0; i < N; ++i, ++m)
perm[i] = m->second;
In my current C++-project I have an STL map which maps integer keys onto objects. An algorithm returns a set of entries. The returned data depends on the algorithm's input and hence cannot be predicted:
class MyClass
{
//...
};
int myAlgorithm(vector<int>::iterator inputIt)
{
// return a key for myMap which is calculated by the current value of inputData
}
int main(int argc, char *argv[])
{
vector<int> inputData;
map<int, MyClass> myMap;
//<fill map with some data>
//<fill inputData>
vector<MyClass> result;
for (vector<int>::iterator it = inputData.begin(); it != inputData.end(); it++)
{
int myMapKey = myAlgorithm(*it);
// count() > 0 means "check whether element exists. Performance can be improved by replacing
// the operator[] and count() calls by map::find(). However, I want to simplify things
// in this example.
if (myMap.count(myMapKey) > 0)
{
// in some cases there is no entry in myMap
result.push_back(myMap[myMapKey]);
}
}
}
As mentioned in the example I can replace map::count() and operator[]-calls with find. The STL-reference says that map::find()'s complexity is logarithmic in size (O(log n)).
I discovered that in most cases the entries in myMap are very close for two sequent entries in the result. Therefore I came to the conclusion that I would achieve better performance if I replaced the map.find() calls by iterators:
map<int, MyClass>::iterator myMapIt = myMap.begin();
for (vector<int>::iterator it = inputData.begin(); it != inputData.end(); it++)
{
int myMapKey = myAlgorithm(*it);
// just increment iterator
while (myMapKey != myMapIt->first)
{
myMapIt++;
// we didn't find anything for the current input data
if (myMapIt == myMap::end() || myMapIt->first > myMapKey)
{
break;
}
}
// I know that I'm checking this twice, but that's not the point of my
// question ;)
if (myMapIt == myMap::end() || myMapIt->first > myMapKey)
{
// probably it would be better to move the iterator back to the position
// where we started searching, to improve performance for the next entry
myMapIt = myMap.begin();
}
else
{
result.push_back(myMapIt.second);
}
}
This concept works but I have a big problem: Depending on the inputData, I have to search forward or backward. Consider that I call the code inside main() multiple times and the inputData changes for these calls. Instead of checking whether to increment or decrement the iterator inside the while-loop, I could decide that before entering the for-loop.
I thought that I'm fine with just switching the map<>::iterator to map<>::reverse_iterator and using rbegin()/rend() instead of begin()/end(). But then I realized that reverse_iterator and iterator have no common base class:
map<int, MyClass>::base_iterator myIt;
if (/* ... */)
{
myMapIt = myMap::begin();
myMapEndIt = myMap::end();
}
else
{
myMapIt = myMap::rbegin();
myMapEndIt = myMap::rend();
}
/* for (...) ... */
That would be great, but there is no base_iterator.
I know a simple workaround for this problem: I just need to copy the whole for-loop and adjust it for both cases:
if (/* ... */)
{
/* for(...) which uses normal iterator in the while-loop */
}
else
{
/* for(...) which uses reverse iterator in the while-loop */
}
Very bad ... Do you know a better solution?
A common base type is unnecessary when the language allows Generic Programming.
What you simply need to realize is that instead of having a long-winded linear functions with several choices along the way, you can have several nested function in which each choice lead to a different call.
Taking your example:
boost::any_iterator start, end;
if (/* ... */) {
start = map.begin(), end = map.end();
} else {
start = map.rbegin(), end = map.rend();
}
// do something with start and end
You can transform the code into the following:
// Define a free-function in the .cpp to help factor common stuff
template <typename FwdIt>
static void dosomething(FwdIt start, FwdIt end) {
// do something with start and end
}
And then inject the call straight into the if/else body:
if (/* ... */) {
dosomething(map.begin(), map.end());
} else {
dosomething(map.rbegin(), map.rend());
}
And one good thing is that you reduce the number of changes of states within your functions and thus their complexity.
Use a templated function. The only place in the Standard library where inheritance is used over templates is IOstreams, as far as I'm aware (and that was a mistake).
template<typename Iterator> ... stuff(Iterator begin, Iterator end) {
// implement loop here
}
if (/*...*/) {
stuff(map.rbegin(), map.rend());
} else {
stuff(map.begin(), map.end());
}
However, I question if you would simply be better off changing to an always O(1) container, like an unordered_map.
You could use templates:
template <typename T>
void myFunction(T start, T end)
{
/* for (...) ... */
}
map<int, MyClass>::base_iterator myIt;
if (/* ... */)
{
myFunction(myMap.begin(), myMap.end());
}
else
{
myFunction(myMap.rbegin(), myMap.rend());
}
From c++14 if you don't want to write template<...> you can let compiler do it for you and use lambda instead create function template.
then call would be like that:
void your_function(auto &some_container, bool from_front) {
auto setter = [&](auto begin, auto end) {
auto no_of_elements_to_change = 3;
for (auto el = begin; el != end; ++el) {
*el = +1000; /// stuff you want to do with last 3 elements
if (--no_of_elements_to_change == 0) {
break;
}
}
};
if (from_front) {
setter(some_container.begin(), some_container.end());
} else {
setter(some_container.rbegin(), some_container.rend());
}
}
With c++20 we will be probably able to do same with std::ranges.
I'm new to Qt and trying to learn the idioms.
The foreach documentation says:
Qt automatically takes a copy of the container when it enters a foreach loop. If you modify the container as you are iterating, that won't affect the loop.
But it doesn't say how to remove an element while iterating with foreach. My best guess is something like:
int idx = 0;
foreach (const Foo &foo, fooList) {
if (bad(foo)) {
fooList.removeAt(idx);
}
++idx;
}
Seems ugly to have to scope idx outside the loop (and to have to maintain a separate loop counter at all).
Also, I know that foreach makes a copy of the QList, which is cheap, but what happens once I remove an element -- is that still cheap or is there an expensive copy-on-modify going on? Yes, deep copy happens.
EDIT : This doesn't seem like idiomatic Qt either.
for (int idx = 0; idx < fooList.size(); ) {
const Foo &foo = fooList[idx];
if (bad(foo)) {
fooList.removeAt(idx);
}
else ++idx;
}
You should better use iterators for that:
// Remove all odd numbers from a QList<int>
QMutableListIterator<int> i(list);
while (i.hasNext()) {
if (i.next() % 2 != 0)
i.remove();
}
If you don't want a copy at all, use iterators. Something like:
QList<yourtype>::iterator it = fooList.begin();
while (it != fooList.end()) {
if (bad(*it))
it = fooList.erase(it);
else
++it;
}
(And make sure you really want to use a QList instead of a QLinkedList.)
foreach is really nice when you want to traverse a collection for inspection, but as you have found, it's hard to reason about when you want to change the structure of the underlying collection (not the values stored in there). So I avoid it in that case, simply because I can't figure out if it is safe or how much copying overhead happens.
If the test function is reentrant, you could also use QtConcurrent to remove the "bad" elements:
#include <QtCore/QtConcurrentFilter>
...
QtConcurrent::blockingFilter(fooList, bad);
Or the STL variant:
#include <algorithm>
...
fooList.erase(std::remove_if(fooList.begin(), fooList.end(), bad),
fooList.end());
Here's an example spin off of the accepted answer, which I prefer purely for readabilty / style (I'm a fan of typedef's and for loops):
class MyClass
{
...
};
typedef QMutableListIterator<MyClass> MyClassIterator;
...
for( MyClassIterator it( myObjList ); it.hasNext(); )
{
auto myObj( it.next() );
if( isBad( myObj ) ) it.remove();
}