Find and update an element in C++11 vector of structs - c++

I have a vector of struct as follows
struct myStruct{
size_t aID;
int bID;
double tobeUpdated;
};
std::vector<myStruct> myVec;
how can I find and update a member of myVec which satisfies aID == someId && bID == otherID in an efficient way in C++11?

Assumes only one to be updated.
// what to search for
size_t aID = 5;
int bID = 7;
find_if(vec.begin(), vec.end(), [aID, bID](const myStruct& obj) { return obj.aID == aID && obj.bID == bID; });

If you want to make it more efficient, it really depends on your usage of the struct and array. If it is possible based on how you use it, then I would store them in an std::map instead. This will allow for easy lookup based on ID's or possibly a combination of ID's. However, if it doesn't actually slow your system down noticeably, then I would say to forgo the optimization and just iterate through each index with that test.

Related

The most efficient nested array container in C++ for reading and writing?

I am a mathematician by training and need to simulate a continuous time Markov chain. I need to use a variant of Gillespie algorithm which relies on fast reading and writing to a 13-dimensional array. At the same time, I need to set the size of each dimension based on users input (they will be each roughly of order 10). Once these sizes are set by the user, they will not change throughout the runtime. The only thing which changes will be the data contained in them. What is the most efficient way of doing this?
My first try was to use the standard arrays but their sizes must be known at the compilation time, which is not my case. Is std::vector a good structure for this? If so, how shall I go about initializing a creature as:
vector<vector<vector<vector<vector<vector<vector<vector<vector<vector<vector<vector<vector<int>>>>>>>>>>>>> Array;
Will the initialization take more time than dealing with an array? Or, is there a better data container to use, please?
Thank you for any help!
I would start by using a std::unordered_map to hold key-value pairs, with each key being a 13-dimensional std::array, and each value being an int (or whatever datatype is appropriate), like this:
#include <iostream>
#include <unordered_map>
#include <array>
typedef std::array<int, 13> MarkovAddress;
// Define a hasher that std::unordered_map can use
// to compute a hash value for a MarkovAddress
// borrowed from: https://codereview.stackexchange.com/a/172095/126857
template<class T, size_t N>
struct std::hash<std::array<T, N>> {
size_t operator() (const std::array<T, N>& key) const {
std::hash<T> hasher;
size_t result = 0;
for(size_t i = 0; i < N; ++i) {
result = result * 31 + hasher(key[i]); // ??
}
return result;
}
};
int main(int, char **)
{
std::unordered_map<MarkovAddress, int> map;
// Just for testing
const MarkovAddress a{{1,2,3,4,5,6,7,8,9,10,11,12,13}};
// Place a value into the map at the specified address
map[a] = 12345;
// Now let's see if the value is present in the map,
// and retrieve it if so
if (map.count(a) > 0)
{
std::cout << "Value in map is " << map[a] << std::endl;
}
else std::cout << "Value not found!?" << std::endl;
return 0;
}
That will give you fast (O(1)) lookup and insert, which is likely your first priority. If you later run into trouble with that (e.g. too much RAM used, or you need a well-defined iteration order, or etc) you could replace it with something more elaborate later.

map comparator for pair of objects in c++

I want to use a map to count pairs of objects based on member input vectors. If there is a better data structure for this purpose, please tell me.
My program returns a list of int vectors. Each int vector is the output of a comparison between two int vectors ( a pair of int vectors). It is, however, possible, that the output of the comparison differs, though the two int vectors are the same (maybe in different order). I want to store how many different outputs (int vectors) each pair of int vectors has produced.
Assuming that I can access the int vector of my object with .inp()
Two pairs (a1,b1) and (a2,b2) should be considered equal, when (a1.inp() == a2.inp() && b2.inp() == b1.inp()) or (a1.inp() == b2.inp() and b1.inp() == a2.inp()).
This answer says:
The keys in a map a and b are equivalent by definition when neither a
< b nor b < a is true.
class SomeClass
{
vector <int> m_inputs;
public:
//constructor, setter...
vector<int> inp() {return m_inputs};
}
typedef pair < SomeClass, SomeClass > InputsPair;
typedef map < InputsPair, size_t, MyPairComparator > InputsPairCounter;
So the question is, how can I define equivalency of two pairs with a map comparator. I tried to concatenate the two vectors of a pair, but that leads to (010,1) == (01,01), which is not what I want.
struct MyPairComparator
{
bool operator() (const InputsPair & pair1, const InputsPair pair2) const
{
vector<int> itrc1 = pair1.first->inp();
vector<int> itrc2 = pair1.second->inp();
vector<int> itrc3 = pair2.first->inp();
vector<int> itrc4 = pair2.second->inp();
// ?
return itrc1 < itrc3;
}
};
I want to use a map to count pairs of input vectors. If there is a better data structure for this purpose, please tell me.
Using std::unordered_map can be considered instead due to 2 reasons:
if hash implemented properly it could be faster than std::map
you only need to implement hash and operator== instead of operator<, and operator== is trivial in this case
Details on how implement hash for std::vector can be found here. In your case possible solution could be to join both vectors into one, sort it and then use that method to calculate the hash. This is straightforward solution, but can produce to many hash collisions and lead to worse performance. To suggest better alternative would require knowledge of the data used.
As I understand, you want:
struct MyPairComparator
{
bool operator() (const InputsPair& lhs, const InputsPair pair2) const
{
return std::minmax(std::get<0>(lhs), std::get<1>(lhs))
< std::minmax(std::get<0>(rhs), std::get<1>(rhs));
}
};
we order the pair {a, b} so that a < b, then we use regular comparison.

Efficient way to search a vector of structs for a specific ID?

I have a vector of structs Data which has an integer data member ID. I need to search if it contains an instance of a specific ID. I had to do it this way:
int DataSize = 0;
for(unsigned count = 0; count < Data.size(); count++)
{
if(ID == Data[count].ID)
DataSize++;
}
Where ID is previously defined. Any more efficient way to search a vector of objects ? Especially when it is a part of an embedded application.
Use std::count_if.
std::count_if(Data.begin(), Data.end(), [&ID](const DataType& data){return ID == data.ID; };
where DataType is the type of elements contained in Data.
Note that there are no real efficiency gains to be had unless Data satisfied some more conditions, for example, being sorted by ID. However, using a standard algorithm improves readability.
With C++11 and lambdas could write a little more expresive as:
If you want to count the struct with ID:
std::count_if(std::cbegin(dataArray), std::cend(dataArray), [ID](const Data& data) {
return data.ID == ID;
});
If you want to known if there is at least one:
bool found_ID = std::cend(dataArray) != std::find_if(std::cbegin(dataArray), std::cend(dataArray), [ID](const Data& data) {
return data.ID == ID;
});
The other algorithms of the STD it's always good to have at hand, some are used only very few time, but could save a lot of debugging (with edge case) and performance problems if implemented by hand.

C++ cast vector type in place

Is it possible to do this without creating new data structure?
Suppose we have
struct Span{
int from;
int to;
}
vector<Span> s;
We want to get an integer vector from s directly, by casting
vector<Span> s;
to
vector<int> s;
so we could remove/change some "from", "to" elements, then cast it back to
vector<Span> s;
This is not really a good idea, but I'll show you how.
You can get a raw pointer to the integer this way:
int * myPointer2 = (int*)&(s[0]);
but this is really bad practice because you can't guarantee that the span structure doesn't have any padding, so while it might work fine for me and you today we can't say much for other systems.
#include <iostream>
#include <vector>
struct Span{
int from;
int to;
};
int main()
{
std::vector<Span> s;
Span a = { 1, 2};
Span b = {2, 9};
Span c = {10, 14};
s.push_back(a);
s.push_back(b);
s.push_back(c);
int * myPointer = (int*)&(s[0]);
for(int k = 0; k < 6; k++)
{
std::cout << myPointer[k] << std::endl;
}
return 0;
}
As I said, that hard reinterpret cast will often work but is very dangerous and lacks the cross-platform guarantees you normally expect from C/C++.
The next worse thing is this, that will actually do what you asked but you should never do. This is the sort of code you could get fired for:
// Baaaad mojo here: turn a vector<span> into a vector<int>:
std::vector<int> * pis = (std::vector<int>*)&s;
for ( std::vector<int>::iterator It = pis->begin(); It != pis->end(); It++ )
std::cout << *It << std::endl;
Notice how I'm using a pointer to vector and pointing to the address of the vector object s. My hope is that the internals of both vectors are the same and I can use them just like that. For me, this works and while the standard templates may luckily require this to be the case, it is not generally so for templated classes (see such things as padding and template specialization).
Consider instead copying out an array (see ref 2 below) or just using s1.from and s[2].to.
Related Reading:
Are std::vector elements guaranteed to be contiguous?
How to convert vector to array in C++
If sizeof(Span) == sizeof(int) * 2 (that is, Span has no padding), then you can safely use reinterpret_cast<int*>(&v[0]) to get a pointer to array of int that you can iterate over. You can guarantee no-padding structures on a per-compiler basis, with __attribute__((__packed__)) in GCC and #pragma pack in Visual Studio.
However, there is a way that is guaranteed by the standard. Define Span like so:
struct Span {
int endpoints[2];
};
endpoints[0] and endpoints[1] are required to be contiguous. Add some from() and to() accessors for your convenience, if you like, but now you can use reinterpret_cast<int*>(&v[0]) to your heart’s content.
But if you’re going to be doing a lot of this pointer-munging, you might want to make your own vector-like data structure that is more amenable to this treatment—one that offers more safety guarantees so you can avoid shot feet.
Disclaimer: I have absolutely no idea about what you are trying to do. I am simply making educated guesses and showing possible solutions based on that. Hopefully I'll guess one right and you won't have to do crazy shenanigans with stupid casts.
If you want to remove a certain element from the vector, all you need to do is find it and remove it, using the erase function. You need an iterator to your element, and obtaining that iterator depends on what you know about the element in question. Given std::vector<Span> v;:
If you know its index:
v.erase(v.begin() + idx);
If you have an object that is equal to the one you're looking for:
Span doppelganger;
v.erase(std::find(v.begin(), v.end(), doppelganger));
If you have an object that is equal to what you're looking for but want to remove all equal elements, you need the erase-remove idiom:
Span doppelganger;
v.erase(std::remove(v.begin(), v.end(), doppelganger)),
v.end());
If you have some criterion to select the element:
v.erase(std::find(v.begin(), v.end(),
[](Span const& s) { return s.from == 0; }));
// in C++03 you need a separate function for the criterion
bool starts_from_zero(Span const& s) { return s.from == 0; }
v.erase(std::find(v.begin(), v.end(), starts_from_zero));
If you have some criterion and want to remove all elements that fit that criterion, you need the erase-remove idiom again:
v.erase(std::remove_if(v.begin(), v.end(), starts_from_zero)),
v.end());

C++ STL: Custom sorting one vector based on contents of another [duplicate]

This question already has answers here:
How do I sort a std::vector by the values of a different std::vector? [duplicate]
(13 answers)
Closed 9 years ago.
This is probably best stated as an example. I have two vectors/lists:
People = {Anne, Bob, Charlie, Douglas}
Ages = {23, 28, 25, 21}
I want to sort the People based on their ages using something like sort(People.begin(), People.end(), CustomComparator), but I don't know how to write the CustomComparator to look at Ages rather than People.
Obvious Approach
Instead of creating two separate vectors/lists, the usual way to handle this is to create a single vector/list of objects that include both names and ages:
struct person {
std::string name;
int age;
};
To get a sort based on age, pass a comparator that looks at the ages:
std::sort(people.begin(), people.end(),
[](auto const &a, auto const &b) { return a.age < b.age; });
In older C++ (pre C++11, so no lambda expressions) you can define the comparison as a member overload of operator< or else as a function-object (an object that overloads operator()) to do the comparison:
struct by_age {
bool operator()(person const &a, person const &b) const noexcept {
return a.age < b.age;
}
};
Then your sort would look something like:
std::vector<person> people;
// code to put data into people goes here.
std::sort(people.begin(), people.end(), by_age());
As for choosing between defining operator< for the class, or using a separate comparator object as I show above, it's mostly a question of whether there's a single ordering that's "obvious" for this class.
In my opinion, it's not necessarily obvious that sorting people would always happen by age. If, however, in the context of your program it would be obvious that sorting people would be done by age unless you explicitly specified otherwise, then it would make sense to implement the comparison
as person::operator< instead of in a separate comparison class the way I've done it above.
Other Approaches
All that having been said, there are a few cases where it really is impractical or undesirable to combine the data into a struct before sorting.
If this is the case, you have a few options to consider. If a normal sort is impractical because the key you're using is too expensive to swap (or can't be swapped at all, though that's pretty rare), you might be able to use a type where you store the data to be sorted along with just an index into the collection of keys associated with each:
using Person = std::pair<int, std::string>;
std::vector<Person> people = {
{ "Anne", 0},
{ "Bob", 1},
{ "Charlie", 2},
{ "Douglas", 3}
};
std::vector<int> ages = {23, 28, 25, 21};
std::sort(people.begin(), people.end(),
[](Person const &a, person const &b) {
return Ages[a.second] < Ages[b.second];
});
You can also pretty easily create a separate index that you sort in the order of the keys, and just use that index to read through the associated values:
std::vector<std::string> people = { "Anne", "Bob", "Charlie", "Douglas" };
std::vector<int> ages = {23, 28, 25, 21};
std::vector<std::size_t> index (people.size());
std::iota(index.begin(), index.end(), 0);
std::sort(index.begin(), index.end(), [&](size_t a, size_t b) { return ages[a] < ages[b]; });
for (auto i : index) {
std::cout << people[i] << "\n";
}
Note, however, that in this case, we haven't really sorted the items themselves at all. We've just sorted the index based on the ages, then used the index to index into the array of data we wanted sorted--but both the ages and names remain in their original order.
Of course, it's theoretically possible that you have such a bizarre situation that none of the above will work at all, and you'll need to re-implement sorting to do what you really want. While I suppose the possibility could exist, I've yet to see it in practice (nor do I even recall seeing a close call where I almost decided that was the right thing to do).
As others have noted, you should consider grouping People and Ages.
If you can't/don't want to, you could create an "index" to them, and sort that index instead. For example:
// Warning: Not tested
struct CompareAge : std::binary_function<size_t, size_t, bool>
{
CompareAge(const std::vector<unsigned int>& Ages)
: m_Ages(Ages)
{}
bool operator()(size_t Lhs, size_t Rhs)const
{
return m_Ages[Lhs] < m_Ages[Rhs];
}
const std::vector<unsigned int>& m_Ages;
};
std::vector<std::string> people = ...;
std::vector<unsigned int> ages = ...;
// Initialize a vector of indices
assert(people.size() == ages.size());
std::vector<size_t> pos(people.size());
for (size_t i = 0; i != pos.size(); ++i){
pos[i] = i;
}
// Sort the indices
std::sort(pos.begin(), pos.end(), CompareAge(ages));
Now, the name of the nth person is people[pos[n]] and its age is ages[pos[n]]
Generally you wouldn't put data that you want to keep together in different containers. Make a struct/class for Person and overload operator<.
struct Person
{
std::string name;
int age;
}
bool operator< (const Person& a, const Person& b);
Or if this is some throw-away thing:
typedef std::pair<int, std::string> Person;
std::vector<Person> persons;
std::sort(persons.begin(), persons.end());
std::pair already implement comparison operators.
It doesn't make sense to keep them in two separate data structures: if you reorder People, you no longer have a sensible mapping to Ages.
template<class A, class B, class CA = std::less<A>, class CB = std::less<B> >
struct lessByPairSecond
: std::binary_function<std::pair<A, B>, std::pair<A, B>, bool>
{
bool operator()(const std::pair<A, B> &left, const std::pair<A, B> &right) {
if (CB()(left.second, right.second)) return true;
if (CB()(right.second, left.second)) return false;
return CA()(left.first, right.first);
}
};
std::vector<std::pair<std::string, int> > peopleAndAges;
peopleAndAges.push_back(std::pair<std::string, int>("Anne", 23));
peopleAndAges.push_back(std::pair<std::string, int>("Bob", 23));
peopleAndAges.push_back(std::pair<std::string, int>("Charlie", 23));
peopleAndAges.push_back(std::pair<std::string, int>("Douglas", 23));
std::sort(peopleAndAges.begin(), peopleAndAges.end(),
lessByPairSecond<std::string, int>());
I would suggest merging these two lists into a single list of structures. That way you can simply define operator < like dirkgently said.
Jerry Coffin answer was fully clear and correct.
A just have a related issue that may grant a good discussion to the topic... :)
I had to reorder the columns of a matrix object (lets say TMatrix< T >) based on the sorting of a vector (lets say sequence)... The TMatrix< T > class do not provide reference access to it's rows (thus I can not create a structure to reorder it...) but conveniently provides a method TMatrix< T >::swap(row1, row2)...
So that's the code:
TMatrix<double> matrix;
vector<double> sequence;
//
// 1st step: gets indexes of the matrix rows changes in order to sort by time
//
// note: sorter vector will have 'sorted vector elements' on 'first' and
// 'original indexes of vector elements' on 'second'...
//
const int n = int(sequence.size());
std::vector<std::pair<T, int>> sorter(n);
for(int i = 0; i < n; i++) {
std::pair<T, int> ae;
ae.first = sequence[i];
ae.second = i;
sorter[i] = ae;
}
std::sort(sorter.begin(), sorter.end());
//
// 2nd step: swap matrix rows based on sorter information
//
for(int i = 0; i < n; i++) {
// updates the the time vector
sequence[i] = sorter[i].first;
// check if the any row should swap
const int pivot = sorter[i].second;
if (i != pivot) {
//
// store the required swaps on stack
//
stack<std::pair<int, int>> swaps;
int source = pivot;
int destination = i;
while(destination != pivot) {
// store required swaps until final destination
// is equals to first source (pivot)
std::pair<int, int> ae;
ae.first = source;
ae.second = destination;
swaps.push(ae);
// retrieves the next requiret swap
source = destination;
for(int j = 0; j < n; j++) {
if (sorter[j].second == source)
destination = j;
break;
}
}
}
//
// final step: execute required swaps
//
while(!swaps.empty()) {
// pop the swap entry from the stack
std::pair<int, int> swap = swaps.top();
destination = swap.second;
swaps.pop();
// swap matrix coluns
matrix.swap(swap.first, destination);
// updates the sorter
sorter[destination].second = destination;
}
// updates sorter on pivot
sorter[pivot].second = pivot;
}
}
I belive that's still O(n log n) since every row that is not in place will swap just one time...
Have fun! :)