I have a function that does some computing and set the value returned into my vector.
#include <vector>
#include <algorithm>
#include <iostream>
void VectorLoop(vector<ClassName>& Vector)
{
float TempFloatVariable = 0.0;
int count = 0;
int update = 0;
while (count != Vector.size())
{
if (Vector[count].getValue() == 100.0) //I hardcode this so i can check if the Value is empty or not
{
//code that set all of the variable from the vector's memory's object
TempFloatVariable = AnotherClass.Formula //does the computing and return the value
//code that gets value from object for overloading
//code that gets value from object for overloading
//code that gets value from object for overloading
Vector[count].setValue(TempFloatVariable);
update++;
}
else
{
count++;
}
}
cout << "Computation completed! (" << update << " record(s) were updated)" << endl;
}
After all of the computing is done, I want to sort them from highest to lowest, base on the Value, but I have no idea how to do so, i tried to hard code it, pulling values out manually 1 by 1 to do comparison, but kept failing. And that would defeat the purpose of using vector, there are many examples of sorting using vector, but 90% of it are int values stored in the vectors.
As IgorTandetnik said: you could do
std::sort(Vector.begin(), Vector.end(), [](const PointTwoD& a, const PointTwoD& b)
{
return a.getcivIndex() > b.getcivIndex();
});
which will use the result from the lambda to sort the vector and should do what you want.
To print the objects in the vector you should do something like this:
for(int i = 0; i < Vector.size(); i++)
{
std::cout << Vector[i] << std::endl; //Or whatever your printing function is.
}
Which will iterate over all the objects in the vector and, as they should already be in descending order from the sort, it will print them out in descending order like you wanted.
Edit:
For non C++11 users: you can define a function that does the comparison
bool compare(const PointTwoD& a, const PointTwoD& b)
{
return a.getcivIndex() > b.getcivIndex();
}
and use it instead of the lambda. Like this:
std::sort(Vector.begin(), Vector.end(), compare);
Use std::sort:
template <class RandomAccessIterator>
void sort (RandomAccessIterator first, RandomAccessIterator last);
The first argument is an iterator to the first element you want to sort. The second argument is the final iterator position after sorting (in other words, one past the final element you want to sort). So to sort you would do this:
std::sort(Vector.begin(), Vector.end());
To determine how the sorting is actually performed, you need to define a < operator for PointTwoD that compares the civ index. Alternately you can create an external function that takes two PointTwoDs as parameters and returns a boolean, and specify it through the third argument to std::sort. If the sort function needs to access private members you'll need to declare it as a friend function in the class definition, though.
You can also inline the compare function in the std::sort call using a lambda if you want, like Phantom posted in his answer.
Related
I've got a vector of pointers for my "Faction" class, stored in such a way:
vector<Faction *> factionptr_;
At this point, I am already able to sort my vector in alphabetical order, so I figured I could use this code here to remove any duplicates that'd show up next to each other:
void Faction::deleteDuplicateFaction(vector<Faction *> &factionptr_){
for (int i = 0; i < factionptr_.size()-1; i++){
if (factionptr_[i]->getFactionname() == factionptr_[i + 1]->getFactionname()){
cout << "it's the same" << endl;
factionptr_.erase(factionptr(i));
}
But I'm getting an error at .erase() and I don't understand:
IntelliSense: no instance of overloaded function "std::vector<_Ty, _Alloc>::erase [with _Ty=Faction *, _Alloc=std::allocator<Faction *>]" matches the argument list
argument types are: (Faction *)
object type is: std::vector<Faction *, std::allocator<Faction *>>
Now I understand that I could be using iterators for this, but I'm not too familiar with them yet. I am definitely not averse to a solution involving iterators though.
Perhaps there's another way?
factionptr is this:
Faction * Faction::factionptr(int k) const{
if ((k < 0) or(k > numberOfFactions())) // elementary error checking
return NULL;
return factionptr_[k]; // returns a pointer to the k-th daughter
}
Wheel reinvention should be discouraged. This is std::unique with a simple custom predicate followed by an erase.
auto pred = [](Faction* a, Faction* b) {
return a->getFactionname() == b->getFactionname();
};
factionptr_.erase(std::unique(factionptr_.begin(), factionptr_.end(), pred),
factionptr_.end());
vector::erase does not take a value for its parameter, it only takes an iterator (or a pair of iterators).
In your case, as you have a index value (i), you can get the right iterator this way:
factionptr_.erase(factionptr_begin()+i);
Note that this will change the length and content of your array, so your loop will not work as expected. One way around this is to only increment the i value when you don't erase an element.
for (int i = 0; i < factionptr_.size()-1){
if (factionptr(i)->getFactionname() == factionptr(i + 1)->getFactionname()){
cout << "it's the same" << endl;
factionptr_.erase(factionptr_begin()+i);
}
else {
i++;
}
}
Also take note of whoiscraig's comment about what happens with an empty vector.
Using the code from cplusplus.com, I am trying to find the max int value in an vector<std::string>.
the vector is in std::string format and there is no choice here.
bool myfn(int i, int j)
{
return i < j;
}
vector<std::string> dat;
dat.push_back(2.1);
dat.push_back(5.3);
for (int l = 0; l < dat.size(); ++l)
{
std::cout << *std::max_element(dat.begin(), dat.end(), myfn) << '\n';
}
expected output:
3
error:
.cpp:76:93: error: no matching function for call to 'max_element(std::vector<std::basic_string<char> >&, std::vector<std::basic_string<char> >::size_type, bool (&)(int, int))'
How do you find the max value in a vector<std::string>?
You're calling max_element with the wrong arguments. It takes two iterators and a function:
template <class ForwardIterator, class Compare>
ForwardIterator max_element (ForwardIterator first, ForwardIterator last,
Compare comp);
You're calling it with a vector and a size. The confusion might stem from the example on the reference you link where they do:
std::min_element(myints, myints +7, myfn)
// ^^^^^^ ^^^^^^^^^
// int* int*
In this case, both myints and myints + 7 are of type int*, and a raw pointer is an iterator. In your case however, you are passing two different types (vector<string> and size_t), neither of which is an iterator. So you need to instead do:
*std::max_element(dat.begin(), dat.end(), myfn)
Or, to illustrate something equivalent to the example in the reference (although definitely prefer the above):
std::string* first = &dat[0];
*std::max_element(first, first + dat.size(), myfn)
Which works because in this case I am passing two string*'s, which are iterators.
(Also based on your usage, dat should be vector<int> not vector<string>.)
You have a vector that is full of strings vector<std::string> dat; but yet your comparison functions takes 2 integers. You might want to either change the type that is stored in the vector or change the comparison function you use. If you use integers then the default comparison operator will do what you want already without you needing to write a custom function.
Also std::max_element expects to get iterators one for the start and one for the end, so you need to change your call to be something like std::max_element(dat.begin(), dat.end(), myfn). You might notice that the loop you have is actually not needed because you already go over that range with the call to std::max_element all this loop does is compute the exact same value multiple times, you only need to compute it once.
Your std::vector dat declaration is wrong as you want to push_back int.
std::max_element and std::min_element returns an iterator not value. You can have a look into the following example
#include <vector>
#include <algorithm>
#include <iostream>
int main()
{
std::vector<int> v {1,2,3,4,6};
auto biggest = std::max_element(std::begin(v), std::end(v));
std::cout << "Max element is " << *biggest
<< " at position " << std::distance(std::begin(v), biggest) << std::endl;
auto smallest = std::min_element(std::begin(v), std::end(v));
std::cout << "min element is " << *smallest
<< " at position " << std::distance(std::begin(v), smallest) << std::endl;
return 0;
}
Pointers can be iterators. This is what allows you to use arrays as a range in standard library functions. myints is an expression that refers to the first element of the array, and myints + 7 refers to one past the end of the array. Equivalently you can do std::begin(myints) and std::end(myints). Standard containers expose iterators in the form of these member functions myvector.begin() and myvector.end(). You pass these iterators, not the container and size, to std::max_element.
By default, std::max_element uses operator< to compare the elements. You don't need a comparator functor in this instance.
Your std::vector's value_type is std::string, but you're trying to pass an int. Either change the value_type to int, or use a string conversion function, i.e. C++11's std::to_string.
Finally, your loop is completely unnecessary. std::max_element operators over a range.
std::vector<int> dat;
dat.push_back(1);
dat.push_back(3);
std::cout << *std::max_element(dat.begin(), dat.end()) << '\n';
I have code that creates several object instances (each instance having a fitness value, among other things) from which I want to sample N unique objects using weighted selection based on their fitness values. All objects not sampled are then discarded (but they need to be initially created to determine their fitness value).
my current code looks something like this:
vector<Item> getItems(..) {
std::vector<Item> items
.. // generate N values for items
int N = items.size();
std::vector<double> fitnessVals;
for(auto it = items.begin(); it != items.end(); ++it)
fitnessVals.push_back(it->getFitness());
std::mt19937& rng = getRng();
for(int i = 0, i < N, ++i) {
std::discrete_distribution<int> dist(fitnessVals.begin() + i, fitnessVals.end());
unsigned int pick = dist(rng);
std::swap(fitnessVals.at(i), fitnessVals.at(pick));
std::swap(items.at(i), items.at(pick));
}
items.erase(items.begin() + N, items.end());
return items;
}
Typically ~10,000 instances are initially created, with N being ~200. The fitness value is non-negative, usually valued at ~70. It could go as high as ~3000, but higher values are increasingly more unlikely.
Is there an elegant way to get rid of the fitnessVals vector? Or perhaps a better way to do this in general? Efficiency is important, but I'm also wondering about good C++ coding practices.
If you're asking whether you can do this just with the items in your items vector, the answer is yes. The following is a rather hideous but none-the-less effective way to do that: I apologize in advance for the density.
This wraps the unsuspecting container iterator in another iterator of our own devices; one that pairs it with a member function of your choice. You may have to dance with const in this to get it to work correctly with your member function choice. That task i leave to you.
template<typename Iter, typename R>
struct memfn_iterator_s :
public std::iterator<std::input_iterator_tag, R>
{
using value_type = typename std::iterator_traits<Iter>::value_type;
memfn_iterator_s(Iter it, R(value_type::*fn)())
: m_it(it), mem_fn(fn) {}
R operator*()
{
return ((*m_it).*mem_fn)();
}
bool operator ==(const memfn_iterator_s& arg) const
{
return m_it == arg.m_it;
}
bool operator !=(const memfn_iterator_s& arg) const
{
return m_it != arg.m_it;
}
memfn_iterator_s& operator ++() { ++m_it; return *this; }
private:
R (value_type::*mem_fn)();
Iter m_it;
};
A generator function follows to create the above monstrosity:
template<typename Iter, typename R>
memfn_iterator_s<Iter,R> memfn_iterator(
Iter it,
R (std::iterator_traits<Iter>::value_type::*fn)())
{
return memfn_iterator_s<Iter,R>(it, fn);
}
What this buys you is the ability to do this:
auto it_end = memfn_iterator(items.end(), &Item::getFitness);
for(unsigned int i = 0; i < N; ++i)
{
auto it_begin = memfn_iterator(items.begin()+i, &Item::getFitness);
std::discrete_distribution<unsigned int> dist(it_begin, it_end);
std::swap(items.at(i), items.at(i+dist(rng)));
}
items.erase(items.begin() + N, items.end());
No temporary array is required. The member function is called for the respective item when required by the discrete distribution (which usually keeps it own vector of weights, and as such replicating that effort would be redundant).
Dunno if you'll get anything helpful or useful out of that, but it was fun to think about.
It's pretty nice that they have a discrete distribution in STL. As far as I know, the most efficient algorithm for sampling from a set of weighted objects (i.e., with probability proportional to weights) is the alias method. There's a Java implementation here: http://www.keithschwarz.com/interesting/code/?dir=alias-method
I suspect that's what the STL discrete_distribution uses anyway. If you're going to be calling your getItems function frequently, you might want to create a "FitnessSet" class or something so that you don't have to build your distribution every time you want to sample from the same set.
EDIT: Another suggestion... If you want to be able to delete items, you could instead store your objects in a binary tree. Each node would contain the sum of the weights in the subtree beneath it, and the objects themselves could be in the leaves. You could select an object through a series of log(N) coin tosses: at a given node, choose a random number between 0 and node.subtreeweight. If it's less than node.left.subtreeweight, go left; otherwise go right. Continue recursively until you reach a leaf.
I would try something like the following (see code comments):
#include <algorithm> // For std::swap and std::transform
#include <functional> // For std::mem_fun_ref
#include <random> // For std::discrete_distribution
#include <vector> // For std::vector
size_t
get_items(std::vector<Item>& results, const std::vector<Item>& items)
{
// Copy the items to the results vector. All operations should be
// done on it, rather than the original items vector.
results.assign(items.begin(), items.end());
// Create the fitness values vector, immediately allocating
// the number of doubles required to match the size of the
// input item vector.
std::vector<double> fitness_vals(results.size());
// Use some STL "magic" ...
// This will iterate over the items vector, calling the
// getFitness() method on each item, and storing the result
// in the fitness_vals vector.
std::transform(results.begin(), results.end(),
fitness_vals.begin(),
std::mem_fun_ref(&Item::getFitness));
//
std::mt19937& rng = getRng();
for (size_t i=0; i < results.size(); ++i) {
std::discrete_distribution<int> dist(fitness_vals.begin() + i, fitness_vals.end());
unsigned int pick = dist(rng);
std::swap(fitness_vals[ii], fitness_vals[pick]);
std::swap(results[i], results[pick]);
}
return (results.size());
}
Instead of returning the results vector, the caller provides a vector into which the results should be added. Also, the original vector (passed as the second parameter) remains unchanged. If this is not something that concerns you, you can always pass just the one vector and work with it directly.
I don't see a way to not have the fitness values vector; the discrete_distribution constructor needs to have the begin and end iterators, so from what I can tell, you will need to have this vector.
The rest of it is basically the same, with the return value being the number of items in the result vector, rather than the vector itself.
This example makes use of a number of STL features (algorithms, containers, functors) which I have found to be useful and part of my day-to-day development.
Edit: the call to items.erase() is superfluous; items.begin() + N where N == items.size() is equivalent to items.end(). The call to items.erase() would equate to a no-op.
I have written a bit of code to match two vector of objects that have some of the same instances of objects within both of the vectors.
The idea is to find the index of the object in the 'main' vector and match that to the object of the other vector.
The index of the main vector would then be used in a map with that object.
I think looking at the code may make my explanation a bit clearer:
ifndef OBJECTMAPMATCH_H
#define OBJECTMAPMATCH_H
#include <map>
#include <utility>
#include <vector>
#include <typeinfo>
#include <iostream>
#include <stdlib.h>
namespace ObjectMapMatch {
...
...
template< class A, class B >
std::map<int, B*>* getIndexMap( std::vector<A*>* x , std::vector<B*>* y, std::map<int, B*>* output )
{
typename std::vector<A*>::iterator Aitr = x->begin();
typename std::vector<A*>::iterator AitrE = x->end();
typename std::vector<B*>::iterator Bitr = y->begin();
typename std::vector<B*>::iterator BitrE = y->end();
for(int index=0; Aitr!=AitrE; ++Aitr, ++index){
//Keep track of original index
int AntupIndex = (*Aitr)->Index();
int match = false;
for(; Bitr!=BitrE; ++Bitr){
int BntupIndex = (*Bitr)->Index();
if( AntupIndex == BntupIndex ){
match = true;
output[index] = (*Bitr);
}
} //End of loop B
if(!match){
std::cout << "ERROR:ObjectMapMatch::getIndexMap: Can not Find Match" << typeid(y).name() << " FOR " << typeid(x).name() << std::endl;
exit(1);
}
}//End of Loop A
}
...
...
}
#endif
As you can see I am basically comparing the two objects with there unique index and if this matches the object will match.
My quesitons:
I know I could have overloaded the comparison operator in the object class, but I was not sure if something like this would be correct??
bool operator==(object1& lhs, object2& rhs){
&lhs == &rhs ? return true : return false;
}
Also,
Is there a shorter/more efficient way of the above code using some STL algorithms (can not use the boost libs) or something smarter??
Mike
There are couple of ways to do this more efficiently than O(n^2).
For example:
Sort elements of the first vector.
Sort elements of the second vector.
Use set_intersection on sorted vectors.
Or:
Put elements of both vectors to multiset (or unordered_multiset).
Keys of the multiset that have more than one element indicate a match.
For both of these methods, you could use pointers or indexes in original vectors instead of the actual elements. Just be careful to provide comparer (to sort, set_intersection and multiset) able to deal with pointers/indexes.
I have a list of objects ("Move"'s in this case) that I want to sort based on their calculated evaluation. So, I have the List, and a bunch of numbers that are "associated" with an element in the list. I now want to sort the List elements with the first element having the lowest associated number, and the last having the highest. Once the items are order I can discard the associated number. How do I do this?
This is what my code looks like (kind've):
list<Move> moves = board.getLegalMoves(board.turn);
for(i = moves.begin(); i != moves.end(); ++i)
{
//...
a = max; // <-- number associated with current Move
}
I would suggest a Schwartzian transform sort. Make a new vector (I recommend vector for more efficient sorting) of pairs of the associated value, and a pointer to its item. Sort the vector of pairs and then regenerate the list from the sorted vector. Since operator< is defined on a std::pair to be comparison by the first item of the pair and then the second, you will get a proper ordering.
Example:
#include <algorithm> // gives you std::sort
#include <utility> // gives you std::pair
typedef double CostType;
typedef std::pair<CostType, Move*> Pair;
// Create the vector of pairs
std::vector<Pair> tempVec;
tempVec.reserve(moves.size());
for (std::list<Move>::iterator i = moves.begin(); i != moves.end(); ++i)
{
CostType cost = calcCost(*i);
Move* ptrToI = &(*i);
tempVec.push_back(Pair(cost, ptrToI));
}
// Now sort 'em
std::sort(tempVec.begin(), tempVec.end());
// Regenerate your original list in sorted order by copying the original
// elements from their pointers in the Pair.
std::list<Move> sortedMoves;
for (std::vector<Pair>::iterator i = tempVec.begin(); i != tempVec.end(); ++i)
{
sortedMoves.push_back(*(i->second));
}
Note that you will need a calcCost function that I have assumed here. This approach has an advantage over creating a comparison function if your comparison value calculation is time consuming. This way, you only pay the cost for calculating the comparison N times instead of 2 * N * log(N).
You could make a comparison function that compares the two elements in the way that you would like.
bool compare_m (const Move &first,const Move &second)
{
if (first.thing_you_are_comparing_on() < second.thing_you_are_comparing_on()) return true;
else return false;
}
Where "thing_you_are_comparing_on" is some member of the Move class that gives you the ordering you want. We use const here to make sure that we are only comparing and not actually changing the objects in the comparison function. You can then call the sort method on the list with compare_m as the comparison function:
moves.sort(compare_m)
Something to note is that if the calculation of the comparison function is particularly expensive it may be worthwhile to precompute all the associated rank numbers before sorting.
This would require adding something to the move class to store the rank for use later:
class Move{
//rest of move class
public:
int rank;
};
list<Move>::iterator iter;
for(iter = moves.begin(); iter != moves.end(); ++iter)
{
//...
(*iter).rank = max; // store the number associated with current Move
}
bool compare_rank (const Move &first,const Move &second)
{
if (first.rank < second.rank) return true;
else return false;
}
std::sort is used to sort STL collections. If the elements in the collection you are sorting can be compared simply by calling operator< and the collection in question is a vector, then sorting is very simple:
std::sort(collection.begin(), collection.end());
If the collection in question is not a vector but a list as in your case, then you can't use the general version of std::sort, but you can use std::list's version instead:
list<int> numbers;
numbers.sort();
STL's sort, along with most other algorithms in the STL, come in two flavors. One is the simple version we have already seen, which just uses operator< to do the comparison of two elements. The other is a 'predicated' version, which instead of using operator< uses a comparison functor you provide. This is what you need to use in your case. There is a predicated version of sort for list, and this is what you need to use in your case.
You can create a functor in a number of ways, but one of the most useful is to derive a class from std::unary_function or from std::binary_function, depending on how many arguments your functor will take -- in your case, two. Override the function-call operator, operator() and add the code that compares two elements:
class compare_functor : public std::binary_function<Move, Move, bool>
{
public:
bool operator(const Move& lhs, const Move& rhs) const
{
int left_val = lhs.Value();
int right_val = rhs.Value();
return left_val < right_val;
};
Here is a complete working example that puts everything together. In this program, instead of having a list of Moves, I have a list of 10 strings. Each string is 6 random characters. The list is populated by the call to generate_n, which uses the functor generator to create each random string. Then I dump that list of strings, along with their values, by calling copy and passing an output iterator that dumps the values to stdout (ostream_iterator). The value of each string is simply a sum of the numeric value of each character, computed by the function strng_val.
Then I sort the list using list's predicated version of sort. The comparison predicate used by sort is evaluator. Then I finally dump the resulting list and the string values to the screen again as above:
#include <cstdlib>
#include <iostream>
#include <list>
#include <string>
#include <algorithm>
#include <ctime>
#include <sstream>
using namespace std;
class generator
{
public:
generator() { srand((unsigned)time(0)); }
string operator()() const
{
string ret;
for( int i = 0; i < 6; ++i )
ret += static_cast<char>((rand()/(RAND_MAX/26)) + 'A');
return ret;
}
};
unsigned string_val(const string& rhs)
{
unsigned val = 0;
for( string::const_iterator it = rhs.begin(); it != rhs.end(); ++it )
val += (*it)-'A'+1;
return val;
};
class evaluator : public std::binary_function<string,string,bool>
{
public:
bool operator()(const string& lhs, const string& rhs) const
{
return string_val(lhs) < string_val(rhs);
}
};
class string_dumper : public std::unary_function<string, string>
{
public:
string operator()(const string& rhs) const
{
stringstream ss;
ss << rhs << " = " << string_val(rhs);
return ss.str();
}
};
int main()
{
// fill a list with strings of 6 random characters
list<string> strings;
generate_n(back_inserter(strings), 10, generator());
// dump it to the screen
cout << "Unsorted List:\n";
transform(strings.begin(), strings.end(), ostream_iterator<string>(cout, "\n"), string_dumper());
// sort the strings according to their numeric values computed by 'evaluator'
strings.sort(evaluator()); // because this is a 'list', we are using list's 'sort'
// dump it to the screen
cout << "\n\nSorted List:\n";
transform(strings.begin(), strings.end(), ostream_iterator<string>(cout, "\n"), string_dumper());
return 0;
}