Say I have the following:
int numFields = 0;
for ( auto & isFieldBlank : InputProcessor::numericFields_isBlank ) {
if ( !isFieldBlank ) {
numFields += 1;
}
}
InputProcessor::numericFields_isBlank is a bool vector of all numeric input values indicating whether the input values are empty true or populated false.
I have two related questions:
Is there a better way to count the populated fields in the vector?
Is there a way to provide a starting index to the for loop iterator?
A range based for loop will always run the entire range, you cant change that unless you adapt the range. What you can do though is use std::count/std::count_if to count the instances for you like
auto count = std::count(container.begin(), container.end(), true);
and to change the start and stop positions you can use std::next to move the iterator like
auto count = std::count(std::next(container.begin(), some_value),
std::next(container.end(), -some_other_value),
true);
Is there a better way to count the populated fields in the vector?
You can simplify the body of the for loop to:
numFields += (!isFieldBlank);
The complete for loop will be
for ( auto & isFieldBlank : InputProcessor::numericFields_isBlank ) {
numFields += (!isFieldBlank);
}
Is there a way to provide a starting index to the for loop iterator?
You certainly can. However, you will need to use a normal for loop, not a range-for loop.
Related
How to get int position of this loop? Thank you.
auto a = vect.begin();
auto b = vect2.begin();
auto c = vect3.begin();
for (; a != vect.end() && b != vect2.end() && c != vect3.end(); a++, b++, c++) {
}
I need to print values of other variable, but I need to get actual unsigned int position of this vector loop.
I need to print double vector using this position of this vector.
And how to get the last index of vector.
My problem is for for loop with multiple vectors and getting index from it next to use only last of indexes.
As Angew shows, a simple indexed loop may be preferable when you need indices.
However, it is possible to get the index from an iterator as well:
auto a = vect.begin();
auto b = vect2.begin();
auto c = vect3.begin();
for (/*the loop conditions*/) {
auto index = a - vect.begin();
}
It is also possible to get the index of a forward iterator using std::distance, but it would be unwise to use it in a loop, since the complexity will be linear for non-random-access iterators.
In the case of forward iterators (and generic code that must support forward iterators), you can write a loop which has both the index variable, and the iterators.
P.S. it is potentially preferable to use pre-increment with iterators. Probably only matters in debug build.
It's simple: if you need indices, don't use iterators:
for (
size_t idx = 0, idxEnd = std::min({vect.size(), vect2.size(), vect3.size()});
idx < idxEnd;
++idx
)
{
auto& obj1 = vect[idx];
auto& obj2 = vect2[idx];
auto& obj3 = vect3[idx];
}
(The above code initialises idxEnd once at the start of the loop, so that it's not needlessly recomputed at each iteration. It's just an optimisation).
I would like to access the second element of ROS-Message message_a.
# ROS-Message message_a
Header header
message_b[] test
ROS-Message 1 contains ROS-Message 2!
# ROS-Message message_b
Header header
uint32[] result
In my main code I loop with a for-each loop through the message test with the datatyp message_a.
for ( message_a::Test1 test : message_a.message_b ) {
uint32_t c = test.result;
}
How can I access for example the second element of message_b? I need that because I want to get the result of the second test.
With the for-each loop that you see above, it will loop through all elements of message_b. How can I change this for-each loop to a general for-loop? Then I could just loop from 2 to 3...
You can change the range-based (aka for-each) loop to an index based for loop like this which iterates over the second, third, ..., and final result of test 42:
std::size_t test_idx = 42; // Second element of results
std::size_t result_start = 1; // start from the second result
std::size_t result_end = your_msg_obj.test.at(test_idx).size(); // run until end of all in the given test
// For loop that iterates over all results in a given test
for ( std::size_t result_idx = result_start; idx < result_end; ++idx ) {
uint32_t c = your_msg_obj.test.at(test_idx).result.at(result_idx);
// ... fancy stuff
}
The ROS documentatation of messages explains that array message fields are generated as std::vector in C++. In your case the field test is of type std::vector<message_b>, result of type std::vector<uint32_t>.
C++ vectors can be accessed in serval ways, you can find them in in this answer. In your case simply accessing the items by index should be possible like:
for(size_t i = 0; i != your_message_a.test.size(); i++)
{
//Access the second result item of each test item
uint32_t c = your_message_a.test[i].result[1];
}
I have a std::vector of some data (Points in my case) and I want to loop over all distinct pairs of elements. The order of the pair is not important (as I am only interested in the distance of the points). With a classic for loop what I would want to do would be something like:
std::vector<double> vec{-1., 3., 5., -8., 123., ...};
for (std::vector<double>::size_type first = 0; first < vec.size(); ++first) {
for (std::vector<double>::size_type second = first+1; second < vec.size();
++second) {
// Compute something using std::fabs(vec.at(first)-vec.at(second))
}
}
My question is now if one can achieve this more elegantly using range based loops.
I wouldn't attempt to coerce it into a range based loop (since contriving the start of the inner loop will be tricky), but I would work directly with the iterators to clarify the loop body and to make the code less dependent on the specific container you're using:
for (auto first = vec.begin(); first != vec.end(); ++first){
for (auto second = first + 1; second != vec.end(); ++second){
// Your vec.at(first) is now simply *first.
}
}
Note that first + 1 is always valid since first is never vec.end() when first + 1 is evaluated.
std::vector::at is also required by the C++ standard to check that the supplied index is in the bounds of the vector (and throw a std::out_of_range exception if it isn't within the bounds), which is an unnecessary overhead in your case.
I provide this answer only because OP want a way of doing that with
range based for loops. It isn't more elegant than ordinary loops.
If your vector doesn't have duplicate numbers you can use reverse iteration instead of beginning from a specific point in the second loop, so that you can use range based for in your iterations.
for reverse iteration by range based for loops you want an adapter class.
template <typename It>
class reverse_adapter
{
public:
reverse_adapter(It rbegin, It rend)
: _rbegin(rbegin), _rend(rend)
{}
It begin() const { return _rbegin; }
It end() const { return _rend; }
private:
It _rbegin;
It _rend;
};
template<typename Container>
reverse_adapter<typename Container::reverse_iterator> make_reverse(Container& container)
{
reverse_adapter<typename Container::reverse_iterator> adapter(std::rbegin(container), std::rend(container));
return adapter;
}
And use this adapter for reverse iteration in second loop.
for(auto val : vec)
{
for (auto second_val : make_reverse(vec)) // Start from last to current item in first loop
{
if (val == second_val) break; // Instead of first + 1 in second loop
auto dif = val - second_val;
}
}
I'm quite new to vector and need some additional help with regards to vector manipulation.
I've currently created a global StringArray Vector that is populated by string values from a text file.
typedef std::vector<std::string> StringArray;
std::vector<StringArray> array1;
I've created a function called "Remove" which takes the input from the user and will eventually compare the input against the first value in the array to see whether it's a match. If it is, the entire row will then deleted and all elements beneath the deleted row will be "shuffled up" a position to fill the game.
The populated array looks like this:
Test1 Test2 Test3
Cat1 Cat2 Cat3
Dog1 Dog2 Dog3
And the remove function looks like this:
void remove()
{
string input;
cout << "Enter the search criteria";
cin >> input;
I know that I will need a loop to iterate through the array and compare each element with the input value and check whether it's a match.
I think this will look like:
for (int i = 0; i < array1.size(); i++)
{
for (int j = 0; j < array1[i].size(); j++)
{
if (array1[i] = input)
**//Remove row code goes here**
}
}
But that's as far as I understand. I'm not really sure A) if that loop is correct and B) how I would go about deleting the entire row (not just the element found). Would I need to copy across the array1 to a temp vector, missing out the specified row, and then copying back across to the array1?
I ultimately want the user to input "Cat1" for example, and then my array1 to end up being:
Test1 Test2 Test3
Dog1 Dog2 Dog3
All help is appreciated. Thank you.
So your loop is almost there. You're correct in using one index i to loop through the outer vector and then using another index j to loop through the inner vectors. You need to use j in order to get a string to compare to the input. Also, you need to use == inside your if statement for comparison.
for (int i = 0; i < array1.size(); i++)
{
for (int j = 0; j < array1[i].size(); j++)
{
if (array1[i][j] == input)
**//Remove row code goes here**
}
}
Then, removing a row is the same as removing any vector element, i.e. calling array1.erase(array1.begin() + i); (see How do I erase an element from std::vector<> by index?)
Use std::list<StringArray> array1;
Erasing an item from an std::vector is less efficient as it has to move all the proceeding data.
The list object will allow you to remove an item (a row) from the list without needing to move the remaining rows up. It is a linked list, so it won't allow random access using a [ ] operator.
You can use explicit loops, but you can also use already implemented loops available in the standard library.
void removeTarget(std::vector<StringArray>& data,
const std::string& target) {
data.erase(
std::remove_if(data.begin(), data.end(),
[&](const StringArray& x) {
return std::find(x.begin(), x.end(), target) != x.end();
}),
data.end());
}
std::find implements a loop to search for an element in a sequence (what you need to see if there is a match) and std::remove_if implements a loop to "filter out" elements that match a specific rule.
Before C++11 standard algorithms were basically unusable because there was no easy way to specify custom code parameters (e.g. comparison functions) and you had to code them separately in the exact form needed by the algorithm.
With C++11 lambdas however now algorithms are more usable and you're not forced to create (and give a reasonable name to) an extra global class just to implement a custom rule of matching.
From this, we know the method to solve the intersection of two sorted arrays. So how to get the intersection of multiple sorted arrays?
Based on the answers of two sorted arrays, we can apply it to multiple arrays. Here are the codes
vector<int> intersectionVector(vector<vector<int> > vectors){
int vec_num = vectors.size();
vector<int> vec_pos(vec_num);// hold the current position for every vector
vector<int> inter_vec; // collection of intersection elements
while (true){
int max_val = INT_MIN;
for (int index = 0; index < vec_num; ++index){
// reach the end of one array, return the intersection collection
if (vec_pos[index] == vectors[index].size()){
return inter_vec;
}
max_val = max(max_val, vectors[index].at(vec_pos[index]));
}
bool bsame = true;
for (int index = 0; index < vec_num; ++index){
while (vectors[index].at(vec_pos[index]) < max_val){
vec_pos[index]++; // advance the position of vector, once less than max value
bsame = false;
}
}
// find same element in all vectors
if (bsame){
inter_vec.push_back(vectors[0].at(vec_pos[0]));
// advance the position of all vectors
for (int index = 0; index < vec_num; ++index){
vec_pos[index]++;
}
}
}
}
Is any better approach to solve it?
Update1
From those two topics 1 and 2, it seem that Hash set is more efficient method to do that.
Update2
To improve the performance, maybe the min-heap can be used instead of vec_pos in my codes above. And the variable max_val holds the current max value of all vectors. So just compare the root value with max_val, if they are same, this element can be put into intersection list.
To get the intersection of two sorted ranges, std::set_intersection can be used:
std::vector<int> intersection (const std::vector<std::vector<int>> &vecs) {
auto last_intersection = vecs[0];
std::vector<int> curr_intersection;
for (std::size_t i = 1; i < vecs.size(); ++i) {
std::set_intersection(last_intersection.begin(), last_intersection.end(),
vecs[i].begin(), vecs[i].end(),
std::back_inserter(curr_intersection));
std::swap(last_intersection, curr_intersection);
curr_intersection.clear();
}
return last_intersection;
}
This looks a lot cleaner than your solution which is too confusing to check for correctness.
It also has optimal complexity.
The standard library algorithm set_intersection may be implemented in any way that uses
at most 2ยท(N1+N2-1) comparisons, where N1 = std::distance(first1, last1) and N2 = std::distance(first2, last2).
first1 etc. are the iterators defining the input ranges. You can check out the actual implementation in the source code of your standard-library if it is open source (like libstd++ or libc++).
This assumes you know the number of containers you are intersecting:
template<class Output, class... Cs>
Output intersect( Output out, Cs const&... cs ) {
using std::begin; using std::end;
auto its = std::make_tuple( begin(cs)... );
const auto ends = std::make_tuple( end(cs)... );
while( !at_end( its, ends ) ) {
if ( all_same( its ) ) {
*out++ = *std::get<0>(its);
advance_all( its );
} else {
advance_least( its );
}
}
return out;
}
To complete simply implement:
bool at_end( std::tuple<Iterators...> const& its, std::tuple<Iterators...> const& ends );
bool all_same( std::tuple<Iterators...> const& its );
void advance_all( std::tuple<Iterators...>& its );
void advance_least( std::tuple<Iterators...>& its );
The first is easy (use indexes trick, compare pairwise, check that you returned true if the tuples are empty).
The second is similar. It should be easier if you compare std::get<i>(its) == std::get<i+1>(its) I think rather than compare all to zero. A special case for empty might be required.
advance_all is even easier.
The last is the tricky one. The requirements are that you advance at least one iterator, and you do not advance the one that dereferences the most, and you advance iterators at most once, and you advance the most you can up to efficiency.
I suppose the easiest method is to find the greatest element, the advance everything less than that by 1.
If you don't know the number of containers you are intersecting, the above can be refactored to use dynamic storage for the iteration. This will look similar to your own solution, except with the details factored out into sub functions.