What I'm trying to do is change this sort
There is a map < string,int> and it is sorted by frequency
typedef map<string,int> word_Count_List;
word_Count_List word_Count;
struct val_Lessthan : binary_function < pair<string,int>, pair<string,int>, bool > {
bool operator() (const pair<string,int>& x, const pair<string,int>& y) const
{return x.second>y.second;}
} val_lt;
and later
vector<pair<string,int> > wordVector;
copy(word_Count.begin(), word_Count.end(), back_inserter(wordVector));
sort(wordVector.begin(), wordVector.end(), val_lt);
I want to print a list of words with their occurrence(which it does now) but change the compare to int * string.length, instead of just int
This is how i'm printing it at the moment
ofstream file_Out;
file_Out.open(file);
for(unsigned int i=0; i<wordVector.size(); ++i) {
file_Out << wordVector[i].first << " " << wordVector[i].second << "\n";
}
file_Out.close();
}
I'm not too good with structs and overloading, can I change the one above or do I need to do something new?
Is it legal to do something like
{return (x.first.length*x.second)>(y.first.length*y.second);}
Related
struct chainout {
LONG cl;
std::string cs;
bool operator<(const chainout&o)const {
return cl < o.cl || cs < o.cs;
}
} ;
struct chainin{
std::string tm;
std::string tdi;
short mss;
LONG pinid;
bool operator<(const chainin&o)const {
return mss < o.mss || pinid < o.pinid || tm<o.tm; //no tdi right now it's always empty
}
};
std::map <chainin,chainout> chainmap;
std::map<chainin,chainout>::iterator it;
chainin ci;
chainout co;
string FADEDevicePinInfo::getNetAtPinIdTmTidMss (const LONG p,const string tm, const string tid,const LONG mss){
ci.tm=tm;
// ci.tdi=tid;
ci.tdi="";
ci.mss=(short)mss;
ci.pinid=p;
for (it=chainmap.begin();it!=chainmap.end();it++){
if(it->first.pinid==ci.pinid && it->first.tm==ci.tm&&it->first.mss==ci.mss && it->first.tdi==ci.tdi){
cout << "BDEBUG: found p["; cout<<it->first.pinid; cout<<"] tm["; cout<<it->first.tm.c_str();cout<<"] mss[";cout<<it->first.mss;cout<<"] : ";cout<<it->second.chainSignal.c_str();cout<<endl;
}
}
it=chainmap.find(ci);
if(it == chainmap.end()){
MSG(SEV_T,("no pin data found for pin[%ld]/tm[%s]/tdi[%s]/mss[%ld]",ci.pinid,ci.tm.c_str(),ci.tdi.c_str(),ci.mss));
}
return it->second.cs;
}
This is both printing the successfully found line, and then throwing the sev_t error due to map::find not returning a match. what did i do wrong?
I added print statements thruout the < function, but it seems to be ordering the map correctly, and when i do the lookup, it seems to find the correct mss/pinid, but then only sees one tm, which is the wrong tm.
As noted in comments, you have a bad comparison operator. If you don't know what order the objects should be sorted in, then neither does std::map or any other sorted container.
When you have multiple things to compare, consider deciding which is most important, and use std::tie to compare them, as demonstrated here:
#include <string>
#include <iostream>
struct chainout {
int cl;
std::string cs;
bool operator<(const chainout&o)const {
return std::tie(cl, cs) < std::tie(o.cl, o.cs);
}
};
int main(){
chainout a{ 1, "b" };
chainout b{ 2, "a" };
std::cout << (a < b) << std::endl;
std::cout << (b < a) << std::endl;
}
The operator< for both of your structs are implemented incorrectly.
std::map requires key comparisons to use Strict Weak Ordering. That means when your structs want to compare multiple fields, they need to compare later fields only when earlier fields compare equal. But you are not checking for that condition. You are returning true if any field in one instance compares less-than the corresponding field in the other instance, regardless of the equality (or lack of) in the other fields. So you are breaking SWO, which causes undefined behavior in std::map's lookups.
Try this instead:
struct chainout {
LONG cl;
std::string cs;
bool operator<(const chainout &o) const {
/*
if (cl < o.cl) return true;
if (cl == o.cl) return (cs < o.cs);
return false;
*/
return (cl < o.cl) || ((cl == o.cl) && (cs < o.cs));
}
};
struct chainin{
std::string tm;
std::string tdi;
short mss;
LONG pinid;
bool operator<(const chainin &o) const {
if (mss < o.mss) return true;
if (mss == o.mss) {
if (pinid < o.pinid) return true;
if (pinid == o.pinid) return (tm < o.tm);
}
return false;
}
};
An easier way to implement this is to use std::tie() instead, which has its own operator< to handle this for you, eg:
struct chainout {
LONG cl;
std::string cs;
bool operator<(const chainout &o) const {
return std::tie(cl, cs) < std::tie(o.cl, o.cs);
}
};
struct chainin{
std::string tm;
std::string tdi;
short mss;
LONG pinid;
bool operator<(const chainin &o) const {
return std::tie(mss, pinid, tm) < std::tie(o.mss, o.pinid, o.tm);
}
};
Either way, then std::map::find() should work as expected, eg:
std::map<chainin, chainout> chainmap;
string FADEDevicePinInfo::getNetAtPinIdTmTidMss (const LONG p, const string tm, const string tid, const LONG mss)
{
chainin ci;
ci.tm = tm;
//ci.tdi = tid;
ci.tdi = "";
ci.mss = (short) mss;
ci.pinid = p;
std::map<chainin, chainout>::iterator it = chainmap.find(ci);
if (it != chainmap.end()) {
cout << "BDEBUG: found"
<< " p[" << it->first.pinid << "]"
<< " tm[" << it->first.tm << "]"
<< " mss[" << it->first.mss << "]"
<< " : " << it->second.cs
<< endl;
}
}
Hey i have a table of teams with the names and the points they have and i'm trying to figure out how to display the last 3 teams with the least amount of points in the table?
It displays all the teams and i want it to display only the last 3 in the table but don't know what way to go about it.
These are my Accessors
string GetName
int GetPoints
int lowest = 1000;
for (int i = 0; i < numTeams; i++)
{
if (league[i].GetPoints() < lowest)
{
lowest = league[i].GetPoints();
}
}
for (int i = 0; i < numTeams; i++)
{
if (league[i].GetPoints() == lowest)
{
cout << "\tThe lowest goals against is: " << league[i].GetName() << endl;
}
}
Actually, you don't need variable lowest, if you would sort the data before printing.
#include <algorithm>
// Sort using a Lambda expression.
std::sort(std::begin(league), std::end(league), [](const League &a, const League &b) {
return a.GetPoints() < b.GetPoints();
});
int last = 3;
for (int i = 0; i < last; i++)
{
cout << "\tThe lowest goals against is: " << league[i].GetName() << endl;
}
U could probably start by sorting your array
#include <algorithm>
std::array<int> foo;
std::sort(foo.begin(), foo.end());
and then Iterate From Your Last Element to your Last - 3. (U can use Reverse Iterators)
for (std::vector<int>::reverse_iterator it = v.rend() ; it != v.rend() + 3;
it++) {
//Do something
}
or by using auto
for (auto it = v.rend() ; it != v.rend() + 3; ++it) {
//Do something
}
In my example I've created test class(TestTeam) to implement several important methods for objects in your task.
I use std::sort method to sort container of objects, by default std::sort compares objects by less(<) operation, so I have overrided operator < for TestTeam object
bool operator < ( const TestTeam& r) const
{
return GetPoints() < r.GetPoints();
}
Also we could pass as third parameter another compare method or lambda method as shown in below answers:
std::sort(VecTeam.begin(), VecTeam.end(), [](const TestTeam& l, const TestTeam& r)
{
return l.GetPoints() < r.GetPoints();
});
And example when we use global method to compare:
bool CompareTestTeamLess(const TestTeam& l, const TestTeam& r)
{
return l.GetPoints() < r.GetPoints();
}
//...
// some code
//...
// In main() we use global method to sort
std::sort(VecTeam.begin(), VecTeam.end(), ::CompareTestTeamLess);
You can try my code with vector as container:
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
// Test class for example
class TestTeam
{
public:
TestTeam(int16_t p, const std::string& name = "Empty name"):mPoints(p), mName(name)
{
};
int16_t GetPoints() const {return mPoints;}
const std::string& GetName() const {return mName;}
void SetName( const std::string& name ) {mName=name;}
bool operator < ( const TestTeam& r) const
{
return GetPoints() < r.GetPoints();
}
private:
int16_t mPoints;
std::string mName;
};
int main(int argc, const char * argv[])
{
const uint32_t COUNT_LOWEST_ELEMENTS_TO_FIND = 3;
// Fill container by test data with a help of non-explicit constructor to solve your task
std::vector<TestTeam> VecTeam {3,5,8,9,11,2,14,7};
// Here you can do others manipulations with team data ...
//Sort vector by GetPoints overloaded in less operator. After sort first three elements will be with lowest points in container
std::sort(VecTeam.begin(), VecTeam.end());
//Print results as points - name
std::for_each( VecTeam.begin(), VecTeam.begin() + COUNT_LOWEST_ELEMENTS_TO_FIND, [] (TestTeam el)
{
std::cout << el.GetPoints() << " - " << el.GetName() << std::endl;
} );
}
I made test class TestTeam only to implement test logic for your object.
If you try launch the program you can get next results:
2 - Empty name
3 - Empty name
5 - Empty name
Program ended with exit code: 0
I have following problem. My vector contains pairs of pairs (see example below).
In the example below I will push_back vector with some "random" data.
What will be best solution to delete the vector element if any of their values will be equal i.e. 100 and update value if less than 100.
i.e.
typedef std::pair<int, int> MyMap;
typedef std::pair<MyMap, MyMap> MyPair;
MyMap pair1;
MyMap pair2;
In first example I want to update this pair because pair1.first is less than 100
pair1.first = 0;
pair1.second = 101;
pair2.first = 101;
pair2.second = 101;
In second example I want to delete this pair because pair2.first is equal to 100
pair1.first = 0;
pair1.second = 101;
pair2.first = 100;
pair2.second = 101;
Using functor "check" I am able to delete one or more elements (in this example just one).
It is possible to increase every value of that pair by 1 using std::replace_if function?
Is there any function that will update this value if any of these values will be lower then "X" and delete if any of these values will be equal "X"?
I know how to do it writing my own function but I am curious.
#include "stdafx.h"
#include<algorithm>
#include<vector>
#include<iostream>
typedef std::pair<int, int> MyMap;
typedef std::pair<MyMap, MyMap> MyPair;
void PrintAll(std::vector<MyPair> & v);
void FillVectorWithSomeStuff(std::vector<MyPair> & v, int size);
class check
{
public:
check(int c)
: cmpValue(c)
{
}
bool operator()(const MyPair & mp) const
{
return (mp.first.first == cmpValue);
}
private:
int cmpValue;
};
int _tmain(int argc, _TCHAR* argv[])
{
const int size = 10;
std::vector<MyPair> vecotorOfMaps;
FillVectorWithSomeStuff(vecotorOfMaps, size);
PrintAll(vecotorOfMaps);
std::vector<MyPair>::iterator it = std::find_if(vecotorOfMaps.begin(), vecotorOfMaps.end(), check(0));
if (it != vecotorOfMaps.end()) vecotorOfMaps.erase(it);
PrintAll(vecotorOfMaps);
system("pause");
return 0;
}
std::ostream & operator<<(std::ostream & stream, const MyPair & mp)
{
stream << "First:First = " << mp.first.first << " First.Second = " << mp.first.second << std::endl;
stream << "Second:First = " << mp.second.first << " Second.Second = " << mp.second.second << std::endl;
stream << std::endl;
return stream;
}
void PrintAll(std::vector<MyPair> & v)
{
for (std::vector<MyPair>::iterator it = v.begin(); it != v.end(); ++it)
{
std::cout << *it;
}
}
void FillVectorWithSomeStuff(std::vector<MyPair> & v, int size)
{
for (int i = 0; i < size; ++i)
{
MyMap m1(i + i * 10, i + i * 20);
MyMap m2(i + i * 30, i + i * 40);
MyPair mp(m1, m2);
v.push_back(mp);
}
}
Use std::stable_partition, along with std::for_each:
#include <algorithm>
//...partition the elements in the vector
std::vector<MyPair>::iterator it =
std::stable_partition(vecotorOfMaps.begin(), vecotorOfMaps.end(), check(0));
//erase the ones equal to "check"
vecotorOfMaps.erase(vecotorOfMaps.begin(), it);
// adjust the ones that were left over
for_each(vecotorOfMaps.begin(), vecotorOfMaps.end(), add(1));
Basically, the stable_partition places all the items you will delete in the front of the array (the left side of the partiton it), and all of the other items to the right of it.
Then all that is done is to erase the items on the left of it (since they're equal to 100), and once that's done, go through the resulting vector, adding 1 to eac
I am having trouble to figure out, how to sort a vector of vector of strings, here is the testing code.
#include <iostream>
#include <vector>
#include <boost/algorithm/string.hpp>
int main(int argc, char** argv) {
std::vector <std::vector <std::string> > data_var;
std::vector <std::string> temp;
std::string str1 = "1,hello3,temp2";
std::string str2 = "2,hello2,temp1";
std::string str3 = "3,hello1,temp3";
boost::split(temp, str1, boost::is_any_of(","));
data_var.push_back(temp);
boost::split(temp, str2, boost::is_any_of(","));
data_var.push_back(temp);
boost::split(temp, str3, boost::is_any_of(","));
data_var.push_back(temp);
// sorting code here...
}
Thanks in advance...
Alright: new -simpler- answer, having learned that vectors are comparable:
//sorting code here...
std::sort(data_var.begin(), data_var.end(), std::greater<std::vector<std::string>>());
If you only want to sort based on the second column, then you just need to provide a custom comparison operator. Once way to do that is:
struct StringListCompare
{
bool operator()(const vector<string>& lhs, const vector<string>& rhs)
{
// what do we do if lhs or rhs don't have two elements?
if (lhs.size() < 2 || rhs.size() < 2)
{
// ?
}
else
{
return lhs[1] < rhs[1];
}
}
} StringListComparer;
int main()
{
// ...
sort(data_var.begin(), data_var.end(), StringListComparer);
}
Edit: If you won't know until runtime which column you'll be sorting on, you can encode that in the sorting object:
class StringListCompare
{
public:
explicit StringListCompare(int column) : m_column(column) {}
bool operator()(const vector<string>& lhs, const vector<string>& rhs)
{
// what do we do if lhs or rhs don't have (m_column + 1) elements?
return lhs[m_column] < rhs[m_column];
}
private:
int m_column;
};
Notice how we've added a constructor that takes which column it'll act on. You can use it like this:
// We set it up so the columns are 0-based:
StringListCompare compare_column_0(0), compare_column_1(1), compare_column_2(2);
cout << "Original:\n" << data_var << endl;
sort(data_var.begin(), data_var.end(), compare_column_2);
cout << "Sorted on column 2:\n" << data_var << endl;
sort(data_var.begin(), data_var.end(), compare_column_1);
cout << "Sorted on column 1:\n" << data_var << endl;
sort(data_var.begin(), data_var.end(), compare_column_0);
cout << "Sorted on column 0:\n" << data_var << endl;
You don't even need to make the local variable if you don't want to:
sort(data_var.begin(), data_var.end(), StringListCompare(2));
cout << "Sorted on 2, no local sort variable:\n" << data_var << endl;
[Code at ideone]
I'm going to assume each vector represents an record of some type, and compare the internal strings from left to right. Obviously the sorter() code is easily replaceable. You should to add a sorter() function somewhere to your code, and pass it to the std::sort algorithm.
bool sorter(const std::vector<std::string>& left, const std::vector<std::string>& right)
{
//go through each column
for(int i=0; i<left.size() && i<right.size()) {
// if left is "more" return that we go higher
if( left[i] > right[i])
return true;
// if left is "less" return that we go lower
else if (left[i] < right[i])
return false;
}
// if left is longer, it goes higher
if (left.size() > right.size())
return true;
else //otherwise, left go lower
return false;
}
int main() {
std::vector <std::vector <std::string> > data_var;
//...
//sorting code here...
std::sort(data_var.begin(), data_var.end(), sorter);
//...
}
Check out the sort function from algorithm:
template <class RandomAccessIterator> void sort ( RandomAccessIterator first, RandomAccessIterator last );
template <class RandomAccessIterator, class Compare> void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );
Click here for an example + docs
Is it possible to create an STL-like container, or even just an STL-style iterator, for an existing array of POD-type elements?
For example, suppose I have an array of ints. It would be convenient to be able to call some of the STL functions, such as find_if, count_if, or sort directly on this array.
Non-solution: copying the entire array, or even just references to the elements. The goal is to be very memory- and time-saving while hopefully allowing use of other STL algorithms.
You can call many of the STL algorithms directly on a regular C style array - they were designed for this to work. e.g.,:
int ary[100];
// init ...
std::sort(ary, ary+100); // sorts the array
std::find(ary, ary+100, pred); find some element
I think you'll find that most stuff works just as you would expect.
You can use an inline function template so that you don't have to duplicate the array index
template <typename T, int I>
inline T * array_begin (T (&t)[I])
{
return t;
}
template <typename T, int I>
inline T * array_end (T (&t)[I])
{
return t + I;
}
void foo ()
{
int array[100];
std::find (array_begin (array)
, array_end (array)
, 10);
}
All the STL algorithms use iterators.
A pointer is a valid iterator into an array of objects.
N.B.The end iterator must be one element past the end of the array. Hence the data+5 in the following code.
#include <algorithm>
#include <iostream>
#include <iterator>
int main()
{
int data[] = {4,3,7,5,8};
std::sort(data,data+5);
std::copy(data,data+5,std::ostream_iterator<int>(std::cout,"\t"));
}
You can use Boost.Array to create a C++ array type with STL semantics.
using arrays:
int a[100];
for (int i = 0; i < 100; ++i)
a[i] = 0;
using boost.arrays:
boost::array<int,100> a;
for (boost::array<int,100>::iterator i = a.begin(); i != a.end(); ++i)
*i = 0;
Update: With C++11, you can now use std::array.
A pointer is a valid model of an iterator:
struct Bob
{ int val; };
bool operator<(const Bob& lhs, const Bob& rhs)
{ return lhs.val < rhs.val; }
// let's do a reverse sort
bool pred(const Bob& lhs, const Bob& rhs)
{ return lhs.val > rhs.val; }
bool isBobNumberTwo(const Bob& bob) { return bob.val == 2; }
int main()
{
Bob bobs[4]; // ok, so we have 4 bobs!
const size_t size = sizeof(bobs)/sizeof(Bob);
bobs[0].val = 1; bobs[1].val = 4; bobs[2].val = 2; bobs[3].val = 3;
// sort using std::less<Bob> wich uses operator <
std::sort(bobs, bobs + size);
std::cout << bobs[0].val << std::endl;
std::cout << bobs[1].val << std::endl;
std::cout << bobs[2].val << std::endl;
std::cout << bobs[3].val << std::endl;
// sort using pred
std::sort(bobs, bobs + size, pred);
std::cout << bobs[0].val << std::endl;
std::cout << bobs[1].val << std::endl;
std::cout << bobs[2].val << std::endl;
std::cout << bobs[3].val << std::endl;
//Let's find Bob number 2
Bob* bob = std::find_if(bobs, bobs + size, isBobNumberTwo);
if (bob->val == 2)
std::cout << "Ok, found the right one!\n";
else
std::cout << "Whoops!\n";
return 0;
}