Mapping a function onto a vector recursively - c++

I have a class called mapTriple that has a method that takes an integer vector and multiplies all the values in vector by a private function of the mapTriple class (the function takes an int, and returns the int *3)
I have already set up the classes and the function that triples the integer. I am stuck on the mapTriple method. The method cannot be iterative, it must be recursive.
vector<int> MapTriple::map(vector<int> myVector)
{
if(myVector.size() == 1)
{
myVector[0] = f(myVector[0]);
return myVector;
}
else
{
map(myVector.erase(myVector.begin()+myVector.size()-1));
myVector[myVector.size()-1] = f(myVector[myVector.size()-1]);
return myVector;
}
}
int f (int a)
{
return (a*3);
}
It currently isnt compiling, it is say there is no matching call to map. I have all the .h files and main files etc

erase does not return the modified vector. It returns an iterator after the removed element (which will be end in your case, so you don't need that). Just pass the modified vector itself.
You currently don't re-add the erased element, so even if your code compiled, you would always be returning a vector of length 1 (and the remaining element would be tripled n times if the vector was originally size n).
The correct else branch should be:
else
{
// Store and remove the last element.
int currentElement = myVector.back();
myVector.erase(myVector.end()-1);
// Recursively process the remaining elements.
map(myVector);
// Process and re-add the above element.
myVector.push_back(f(currentElement));
return myVector;
}
However, instead of erasing elements and re-adding them, you could work with the iterators.
using Iterator = std::vector<int>::iterator;
void MapTriple::map(Iterator start, Iterator end)
{
// No elements remaining?
if (start == end)
return;
// Process first element.
*start = f(*start);
// Process remaining elements recursively.
map(start+1, end);
}
While this is pretty elegant, it would of course be even simpler to do this with a simple for loop:
for (auto& e : myVector) e = f(e);
or std::transform:
std::transform(myVector.begin(), myVector.end(), myVector.begin(),
[this](int e) -> { return f(e); });`
It should also be noted that map is probably a mediocre name for this method, if you did using namespace std; as seems to be the case (see also Why is "using namespace std" considered bad practice?).

Related

Unique elements in unordered_set, erasing and adding while iterating?

I am trying to implement a recursion wherein, I'm passing an unordered_set<int> by reference/alias, to reduce space and time complexity. In order to do this, I must iteratively do the following, remove an element, call recursively, and then remove the element from the unordered_set.
This is a sample code for the recursive function for printing all permutations of a vector<int> A is as follows,
void recur(int s, vector<int> &A, vector<int> &curr, vector<vector<int>> &ans, unordered_set<int> &poses){
if(s == A.size()){
ans.push_back(curr);
return;
}
for(unordered_set<int>::iterator it = poses.begin() ; it != poses.end() ; it++){
int temp = *it;
curr[temp] = A[s];
poses.erase(it);
recur(s + 1, A, curr, ans, poses);
poses.insert(temp);
curr[temp] = -1;
}
}
You can assume that I'm passing curr with all -1s initially.
When adding iterating through an unordered_set it is guaranteed to find all unique elements. I was wondering whether it would be the same if I remove and add elements back while iterating. Will the position of the element change in the hashset, or is it dependent on the implementation.
If this is incorrect could someone also suggest some other way to go about this, since I do not want to pass by value, since it would copy the entire thing for all recursive calls on the stack. Any help would be appreciated.

How to use an iterator pointing to a vector of structs c++?

I need help with my code. I don't understand how to use the returned pointers to access elements in a struct stored in a vector :
struct receptionEvents
{
int chFreqIndex; //0
int chSFIndex; //1
simtime_t endReceptionTime ;
double SNR; //2
bool collidedFlag; //0= false(Not Corrupted) 1=Corrupted
};
std::vector<receptionEvents> buffRxEvents;
Now in main function I am trying to find all structs named receptionEvents that match a certain chFreqIndex using the below line :
int chFreqIndexCheck == 4;
auto vpit = find_if( buffRxEvents.begin(), buffRxEvents.end(), [&]
(receptionEvents const & m) { return m.chFreqIndex == chFreqIndexCheck;} );
Now my problem is how to use the vpit iterator to iterate over all found entries in my vector and how to access the data variables of each. Can any one help please?
The std::find family of functions returns an iterator to a single element (or end if nothing is found).
If you want to get all elements that matches your condition, then you could use std::copy_if to copy to a new container (possibly with the help of std::back_inserter).
You can of course have your own loop, calling std::find_if multiple times and pass the previous vpit plus one as the beginning of the range you search through.
Or use std::for_each or a range-based for loop with a check for the current element to see if it matches your condition.
std::find_if only finds the first occurence. But you could search the next element beginning at the successor of the currently found element, such as:
auto vpit = buff.begin();
while(vpit != buff.end())
{
vpit = std::find_if(vpit, buff.end(), [](/*...*/){ /*...*/ });
if(vpit != buff.end())
{
// use it
++vpit; // for not finding current element AGAIN!
}
}
Simpler, though, is a simple range based for loop:
for(auto e : buff)
{
if( /* ... */ )
{ /* ... */ }
}
Edit:
but how exactly can I use it
You can just use it as if it was a pointer: *vpit to access the data the iterator "points to", vpit->x to access a member of, if data is a complex type (as in your example).
Example:
receptionEvents someCopy = *vpit; // copies entire struct
int cfIndex = vpit->chFreqIndex;

C++ How to delete nodes in a vector

So I have created a binary search tree that is stored within an array. This binary search tree (BST) stores a user input ID, Age, and Name, then places it within the array sorted in ascending order by the ID.
I'm attempting to write a delete function that takes a user input ID, loops through the vector, and if it finds a matching ID, it deletes it.
However, I can't seem to get BinaryTree.erase() to work due to an error.
Severity Code Description Project File Line Suppression State
Error (active) E0304 no instance of overloaded function "std::vector<_Ty, _Alloc>::erase [with _Ty=Node,
_Alloc=std::allocator]" matches the argument list Project_4CS210
After erasing, I plan on organizing the vector so that there aren't any open spots, however, I want to make sure that I can delete the node first. Any suggestions? I am a beginner, so most of this is rather new to me.
Here's my delete function.
#include "BinaryTree.h"
#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int index;
struct Node
{
int ID;
int age;
string name;
Node()
{
}
Node(int id, int Age, string nm)
{
this->ID = id;
this->age = Age;
this->name = nm;
}
};
vector<Node> binaryTree;
void BST::Delete()
{
int input_id;
cout << "What is the ID of the person to be deleted" << endl;
cin >> input_id;
for (unsigned int i = 0; i < binaryTree.size(); i++)
{
if (input_id == binaryTree.at(i).ID)
binaryTree.erase(i);
}
}
std::vector::erase takes an iterator, not an index.
You can use binaryTree.begin() + i to get the iterator for the i-th element of a vector (note that some containers have iterator types without +, so you'd need to use std::advance there).
Overall, binaryTree.erase(binaryTree.begin() + i) should do the job you want, but for what you are trying to do you could also look into std::remove_if.
To expand on this last point (because someone in the comments mentioned the remove/erase idiom):
vector.erase(std::remove_if(vector.begin(),
vector.end(),
[](const auto& element) { return condition(element); }),
vector.end());
This will remove all elements from the vector where condition(element) returns true, and is generally better than iterating over the vector by hand:
If you want to remove more than one element with your method, you might miss some. Take a vector where the elements you want to remove are at indices i and i + 1. Then, you remove the element at index i normally, and the element at i + 1 moves to index i - however, in the next iteration you already check index i + 1, so you miss the item that you wanted to remove
Each time you remove an element from the vector, all the elements behind that are moved around in memory. If your items are fairly big, that can be expensive. Using remove_if should ensure that each element isn't moved more than necessary, which can be more efficient especially if you remove many elements.
You shouldn't remove elements from vector while iterating over it, you can miss some indexes while iterating, use std::remove_if to send elements needed to remove at the end of vector and then erase them from vector with erase() method:
auto It = std::remove_if(binaryTree.begin(), binaryTree.end(), [input](const Node& node)
{
if( node.ID == input )
{
return true;
}
return false;
});
binaryTree.erase(It,binaryTree.end());
Method erase() accepts iterators to remove range or one iterator to remove one element. std::remove_if will return iterator for the first elements pushed at the end to remove.
Considering you wish to remove all the items in the vector or a specific item. You can actually erase items from a vector using erase while iterating. Keep in mind the erase actually provides you with the iterator to the next item. So you may not need to increment the iterator unless it fulfills the condition.
Here is a sample code:
for (std::vector<Node>::iterator it = binaryTree.begin(); it != binaryTree.end();)
{
if(it == yourItem) //Conditional check if it matches with your object.
{
it = binaryTree.erase(it);
}
else
{
++it;
}
}
You can see that i am actually getting the iterator to the next item in the list without incrementing it. You can process it in whatever way you may like.

What is the std::vector::iterator's index in the vector?

I have an std::vector<Bullet> bullets and in the for-loop below I want to remove a bullet from the vector if it's not alive anymore.
My plan is to remove the element with pop_back(). If there are more than one element in the vector I want to first swap the element that is to be removed with the last element in the vector, and then call pop_back().
for (std::vector<Bullet>::iterator b = bullets.begin(); b != bullets.end(); ++b) {
if(!b->isAlive()) {
if (bullets.size() > 1) {
std::iter_swap(bullets + ..., bullets.end());
}
bullets.pop_back();
}
}
The problem is the first parameter in iter_swap. I looked up http://www.cplusplus.com/reference/algorithm/iter_swap/ and the syntax for the first parameter is the vector + the position of the element.
How do I find out b's index in the vector?
If the condition governing whether an element is to be removed or not is :
object->isAlive()
Then you should use an STL way to do the removal, namely the erase-remove idiom :
bullets.erase(std::remove_if(bullets.begin(), bullets.end(),
[](Bullet const& b) {
return !b.isAlive();
}), bullets.end());
Now, to answer your particular question an iterator's it index in a vector v can be obtained like so :
auto indx = std::distance(v.begin(), it);
There's an easier way to filter a std::vector.
#include <algorithm>
auto part = std::remove_if(
bullets_.begin(),
bullets_.end(),
[](const Bullet &bullet) { return !bullet.isAlive(); });
bullets_.erase(part, bullets_.end());
This will partition the vector into the alive and dead bullets, and then you delete the segment with the dead bullets.
The std::remove_if() function is like partition() but only the order of the first partition is preserved.

Erasing element from Vector

In C++, how can I delete an element from a vector?
Delete it right from where it is, i.e. let the vector resize
Swap the element to be deleted with the last element s.t. pop_back() can be used (which I hope doesn't involve copying everything around...)
For (1), I've tried the following, but I'm not quite sure if it does what it is supposed to do (remove the item passed to removeItem() ), and it doesn't seem very elegant:
vector<Item*> items;
// fill vector with lots of pointers to item objects (...)
void removeItem(Item * item) {
// release item from memory
if (int i = getItemIdIfExists(item) != -1) {
items.erase (items.begin()+i);
}
}
int getItemIdIfExists(Item * item) {
// Get id of passed-in Item in collection
for (unsigned int i=0; i<items.size(); i++) {
// if match found
if (items[i] == item) return i;
}
// if no match found
return -1;
}
The standard remove+erase idiom removes elements by value:
#include <vector>
#include <algorithm>
std::vector<int> v;
v.erase(std::remove(v.begin(), v.end(), 12), v.end());
remove reorders the elements so that all the erasees are at the end and returns an iterator to the beginning of the erasee range, and erase actually removes the elements from the container.
This is as efficient as you can get with a contiguous-storage container like vector, especially if you have multiple elements of the same value that all get erased in one wash.
void removeItem(Item*item){
for(int i=0; i<items.size(); i++){
if (items[i]==item){
swap(items[i], items.back());
items.pop_back();
return;
}
}
}
Though, if the order doesn't matter, why not just use a std::set?
Delete it right from where it is, i.e. let the vector resize
That's what erase does.
Swap the element to be deleted with the last element s.t. pop_back() can be used (which I hope doesn't involve copying everything around...)
That's what remove does, except that it preserves the order of the remaining objects so it does involve copying everything around.
What you've done could be written as:
items.erase(
std::remove(
items.begin(), items.end()
, item
)
, items.end()
);
The difference with your code being that this will actually remove all items valued item, instead of just the first one.