I want to insert object of struct one as a unique key in map. So i have written operator() function but find is not working even element exist in map.
#include <iostream>
#include<map>
#include <stdio.h>
#include <string.h>
#include <math.h>
using namespace std;
struct one
{
char* name_;
double accuracy_;
one(char* name, double accuracy)
{
name_ = name;
accuracy_ = accuracy;
}
};
const float Precision = 0.000001;
struct CompLess:public std::binary_function<const one, const one, bool>{
bool operator()(const one p1, const one p2) const
{
if (strcmp(p1.name_, p2.name_)<0)
{
return true;
}
if(((p1.accuracy_) - (p2.accuracy_)) < Precision and
fabs((p1.accuracy_) - (p2.accuracy_))> Precision)
{
return true;
}
return false;
}
};
typedef map<const one,int,CompLess> Map;
int main( )
{
one first("box",30.97);
one first1("war",20.97);
Map a;
a.insert(pair<one,int>(first,1));
a.insert(pair<one,int>(first1,11));
if(a.find(first1) == a.end())
{
cout<<"Not found"<<endl;
}
else
{
cout<<"Found"<<endl;
}
return 0;
}
Your comparison class doesn't induce a strict ordering. You should change it to this:
bool operator()(const one p1, const one p2) const
{
if (strcmp(p1.name_, p2.name_) == 0)
{
if (((p1.accuracy_) - (p2.accuracy_)) < Precision and
fabs((p1.accuracy_) - (p2.accuracy_))> Precision)
{
return true;
}
}
return false;
}
In your version first1 was less than first because strcmp("war", "box") > 0 (first condition is false) and 20.97 < 30.97 (second condition is true), but in the same time first was less than first1, because strcmp("box", "war") < 0 (first condition is true). You should compare the second dimension only if the first one is equal - that's the good rule of thumb for less comparisons.
Related
i am new to C++(also english).
i want to search {1,2,3} in the map and if it exists , print TRUE on screen
but i can not
my code comes below
can you help me?
#include <iostream>
#include <map>
#include <iterator>
#define PKT_UNIT_MAX_LEN 10000
using namespace std;
struct PKT_UNIT
{
int len;
unsigned int checksum;
unsigned char data[PKT_UNIT_MAX_LEN];
};
int main()
{
map<int,PKT_UNIT> maharan;
maharan.insert(pair<int,PKT_UNIT>(1,{1,2,3}));
map<int,PKT_UNIT> ::iterator it;
it=maharan.begin();
for(it=maharan.begin(); it != maharan.end(); it++ )
{
if (maharan.find(it)!=maharan.end())
{
if (it->second.len==1 && it->second.checksum==2 && it->second.data==3)
cout<<"TRUE"<<endl;
}
return 0;
}
map::find takes something comparable to the key_type, not the mapped_type, and certainly not an iterator. Searching for the value is not what std::map is designed to support. You can instead use the generic searching algorithms.
bool operator==(const PKT_UNIT& lhs, const PKT_UNIT& rhs)
{
return (lhs.len == rhs.len)
&& (lhs.checksum == rhs.checksum)
&& std::equal(lhs.data, lhs.data + lhs.len, rhs.data);
}
int main()
{
PKT_UNIT needle{1,2,3};
std::map<int,PKT_UNIT> maharan;
maharan.insert(pair<int,PKT_UNIT>(1,needle));
auto it = std::find_if(maharan.begin(), maharan.end(), [&needle](auto & item){ return item.second == needle; });
if (it != maharan.end())
{
std::cout << "TRUE";
}
return 0;
}
You should overload the equality operator for PKT_UNIT. Then you should just use std::map::find to find what you are looking for.
bool operator==(const PKT_UNIT& lhs, const PKT_UNIT& rhs)
{
return (lhs.len == rhs.len) &&
(lhs.checksum == rhs.checksum) &&
std::equal(lhs.data,lhs.data + PKT_UNIT_MAX_LEN,rhs.data);
}
The you can do something like this:
PKT_UNIT goal {1,2,3};
for (const auto& e : maharan)
{
if (e.second == goal)
{
std::cout << "TRUE\n";
break;
}
}
Also, as it seems you don't need the key, maybe you want to use std::set and use a search algorithm, or std::unordered_set, in which case you wouldn't need a search algorithm at all.
I have a vector called:
vector<MiniPair> miniPairVector;
MiniPair object has 2 property inside,1 is an integer docNumber other is a string word
I am trying to clear duplicates in this vector which means that if docNumber and word exist in another object inside vector remove the duplicates
This is what i have tried but it is producing an infinite loop:
for (int i = 0; i < miniPairVector.size(); i++) {
for (int k = i + 1; k < miniPairVector.size(); k++) {
if (miniPairVector[i].getDocNumber() == miniPairVector[k].getDocNumber() && miniPairVector[i].getWord() == miniPairVector[k].getWord()) {
cout << "i am erasing" << endl;
miniPairVector.erase(miniPairVector.begin() + k);
}
}
}
this is the minipair class:
#pragma once
// classes example
#ifndef MINIPAIR_H
#define MINIPAIR_H
#include <iostream>
using namespace std;
class MiniPair {
friend bool operator<(MiniPair const &a, MiniPair const &b) {
return a.docNumber < b.docNumber || a.docNumber == b.docNumber && a.word < b.word;
}
friend bool operator==(MiniPair const &a, MiniPair const &b) {
return a.docNumber == b.docNumber && a.word == b.word;
}
private:
string word;
int docNumber;
public:
MiniPair();
MiniPair(string word, int docNumber);
string getWord();
int getDocNumber();
};
#endif
My presumption is that you are doing this for a class.
First, while this may not be relevant for the problem you're solving write now because of class imposed constraints, this is a poor way of implementing this. When implemented correctly the number of comparisons will be something like miniPairVector.size() * miniPairVector.size(). That's a lot of comparisons, and way more than you actually need.
If I were trying to do this in a non-toy (or non-assignment) program, I would use the <algorithm> section of the standard library. I would use ::std::sort and then ::std::unique.
Here's how I would do it using those two:
#include <algorithm>
void remove_dupes(::std::vector<MiniPair> &minipair_vec)
{
::std::sort(minipair_vec.begin(), minipair_vec.end(),
[](MiniPair const &a, MiniPair const &b) -> bool {
return (a.getDocNumber() < b.getDocNumber())
|| ((a.getDocNumber() == b.getDocNumber())
&& (a.getWord() < b.getWord())));
}); // End lambda and sort.
auto newend = ::std::unique(minipair_vec.begin(), minipair_vec.end(),
[](MiniPair const &a, MiniPair const &b) -> bool {
return a.getDocNumber() == b.getDocNumber()
&& a.getWord() == b.getWord();
}); // End lambda and unique.
minipair_vec.resize(newend - minipair_vec.begin());
}
I have tested it, so it should work just fine.
The general lesson is that if you find yourself looping, go through this set of questions:
Am I indexing into a linear data structure? If so, why am I using indexes instead of iterators?
Is there an algorithm that already does what I need, or can a couple of algorithms be easily composed to do what I need?
The code I presented should run in a time that's proportional to minipair_vec.size() * ::std::log2(minipair_vec.size()). The code you wrote would run in a time proportional to minipair_vec.size() * minipair_vec.size() (once you got it to work), which is a lot longer for a large list.
A C++98 solution:
#include <algorithm>
#include <string>
#include <vector>
struct MiniPair {
int docNumber;
std::string word;
friend bool operator<(MiniPair const &a, MiniPair const &b) {
return a.docNumber < b.docNumber || a.docNumber == b.docNumber && a.word < b.word;
}
friend bool operator==(MiniPair const &a, MiniPair const &b) {
return a.docNumber == b.docNumber && a.word == b.word;
}
};
int main() {
std::vector<MiniPair> miniPairVector;
// fill miniPairVector with data
std::sort(miniPairVector.begin(), miniPairVector.end());
miniPairVector.erase(std::unique(miniPairVector.begin(), miniPairVector.end()), miniPairVector.end());
}
I am using std::map and a list to keep track of windowing over elements and associated scores. When a window is full, I want to pop an element off the windows queue and remove it from the map. Because there can be duplicates, the map keeps track of how many times each element in the window was encountered. I'm also using an ordered map so that I can keep getting the minimum values in a given window.
My problem is that find() is returning end() when it is not expected to.
And when I iterate through the map, I find the element to be present. I don't want to sacrifice the logarithmic complexity of using map.
tl;dr: std::map says an element isn't in the map. A manual scan says it is.
[Edit: Bryan Chen's suggestion fixed the map. Thank you!]
#include <cstdint>
#include <cstdio>
#include <cinttypes>
#include <map>
#include <list>
#include <vector>
#include "util.h"
#include "kmerutil.h"
namespace kpg {
struct elscore_t {
uint64_t el_, score_;
INLINE elscore_t(uint64_t el, uint64_t score): el_(el), score_(score) {
LOG_ASSERT(el == el_);
LOG_ASSERT(score == score_);
}
INLINE elscore_t(): el_(0), score_(0) {}
inline bool operator <(const elscore_t &other) const {
return score_ < other.score_ || el_ < other.el_; // Lexicographic is tie-breaker.
}
inline bool operator ==(const elscore_t &other) const {
return score_ == other.score_ && el_ == other.el_; // Lexicographic is tie-breaker.
}
std::string to_string() const {
return std::to_string(el_) + "," + std::to_string(score_);
}
};
struct esq_t: public std::list<elscore_t> {
};
typedef std::map<elscore_t, unsigned> esmap_t;
class qmap_t {
// I could make this more efficient by using pointers instead of
// elscore_t structs.
// *maybe* TODO
// Could also easily templatify this module for other windowing tasks.
esq_t list_;
#if !NDEBUG
public:
esmap_t map_;
private:
#else
esmap_t map_;
#endif
const size_t wsz_; // window size to keep
public:
void add(const elscore_t &el) {
auto it(map_.upper_bound(el));
if(it->first == el) ++it->second;
else map_.emplace(el, 1);
}
void del(const elscore_t &el) {
auto f(map_.find(el));
if(f == map_.end()) {
LOG_DEBUG("map failed :(\n");
for(f = map_.begin(); f != map_.end(); ++f)
if(f->first == el)
break;
}
LOG_ASSERT(f != map_.end());
if(--f->second <= 0)
map_.erase(f);
}
uint64_t next_value(const uint64_t el, const uint64_t score) {
list_.emplace_back(el, score);
LOG_ASSERT(list_.back().el_ == el);
LOG_ASSERT(list_.back().score_ == score);
add(list_.back());
if(list_.size() > wsz_) {
//fprintf(stderr, "list size: %zu. wsz: %zu\n", list_.size(), wsz_);
//map_.del(list_.front());
del(list_.front());
list_.pop_front();
}
LOG_ASSERT(list_.size() <= wsz_);
return list_.size() == wsz_ ? map_.begin()->first.el_: BF;
// Signal a window that is not filled by 0xFFFFFFFFFFFFFFFF
}
qmap_t(size_t wsz): wsz_(wsz) {
}
void reset() {
list_.clear();
map_.clear();
}
};
}
This is not a valid strict weak ordering:
return score_ < other.score_ || el_ < other.el_;
You have elscore_t(0, 1) < elscore_t(1, 0) and elscore_t(1, 0) < elscore_t(0, 1).
As T.C. pointed out in his answer, your operator< is not correct.
You can use std::tie to do lexicographical comparison
return std::tie(score_, el_) < std::tie(other.score_, other.el_);
Otherwise you can do
if (score_ == other.score_) {
return el_ < other.el_; // use el_ to compare only if score_ are same
}
return score_ < other.score_;
Have a issue when I'm trying to find element in a custom ordered set.
File: c:\program files (x86)\microsoft visual studio 10.0\vc\include\xtree
Line: 1746
Expression: invalid operator<
I need a set of strings where the elements are ordered accordingly my needs.
Comparator object:
struct OrderComparator {
public:
static map<string,int> valueOrder;
bool operator()( const string lhs, const string rhs ) {
map<string,int>::iterator resultLhs,resultRhs;
resultLhs = valueOrder.find(lhs);
resultRhs = valueOrder.find(rhs);
if (resultLhs == valueOrder.end() || resultRhs == valueOrder.end())
{
return false;
}
else {
bool result = resultLhs->second <= resultRhs->second;
return result;
}
}
static map<string,int> create_map()
{
map<string,int> m;
m["A"] = 1;
m["B"] = 2;
m["C"] = 3;
m["D"] = 4;
return m;
}
};
Comparator is working fine!
But when I'm trying to search in the set getting mentioned error.
typedef set<string, OrderComparator> TREESET_CMP;
...
TREESET_CMP::iterator it = myTree.find(obj); <-fails
...
Will be glad if some one can tell me why this is happening and how to fix it.
Full working Mini Example:
#include "stdafx.h"
#include <string>
#include <set>
#include <map>
#include <iterator>
#include <algorithm>
using namespace std;
#include <stdio.h>
#include <tchar.h>
struct OrderComparator {
public:
static map<string,int> valueOrder;
bool operator()( const string lhs, const string rhs ) {
map<string,int>::iterator resultLhs,resultRhs;
resultLhs = valueOrder.find(lhs);
resultRhs = valueOrder.find(rhs);
if (resultLhs == valueOrder.end() || resultRhs == valueOrder.end())
{
return false;
}
else {
bool result = resultLhs->second <= resultRhs->second;
return result;
}
}
static map<string,int> create_map()
{
map<string,int> m;
m["A"] = 1;
m["B"] = 2;
m["C"] = 3;
m["D"] = 4;
return m;
}
};
map<string,int> OrderComparator::valueOrder = OrderComparator::create_map();
typedef set<string, OrderComparator> TREESET_CMP;
int _tmain(int argc, _TCHAR* argv[])
{
TREESET_CMP myTree;
myTree.insert("B");
myTree.insert("C");
myTree.insert("A");
TREESET_CMP::const_iterator it = myTree.find("A");
system("PAUSE");
}
Your comparison doesn't define a strict weak ordering
A strict weak ordering must have these invariants (quoted from the link above)
Irreflexivity f(x, x) must be false.
Antisymmetry f(x, y) implies !f(y, x)
Transitivity f(x, y) and f(y, z) imply f(x, z).
Transitivity of equivalence Equivalence (as defined above) is transitive: if x is equivalent to y and y is equivalent to z, then x is equivalent to z. (This implies that equivalence does in fact satisfy the mathematical definition of an equivalence relation.)
Yours fails at least Irreflexivity (comparing an object to itself must be false) and Antisymmetry (if x is less-than y, then y is not less-than x)
Basically, <= is not a valid ordering, because x <= x returns true, which means you can never find an element in the set. To find an element the set looks for an element with the property !cmp(key, element) && !cmp(element, key) but that can never work for your ordering.
The simplest fix might be to change <= to <, but there could be other problems.
Your comparator can be this:
bool operator()( const string &lhs, const string &rhs ) {
map<string,int>::iterator resultLhs,resultRhs;
resultLhs = valueOrder.find(lhs);
resultRhs = valueOrder.find(rhs);
if (resultLhs == valueOrder.end()) return false;
if (resultRhs == valueOrder.end()) return true;
return resultLhs->second < resultRhs->second;
}
You can replace 2 lines to:
if (resultRhs == valueOrder.end()) return false;
if (resultLhs == valueOrder.end()) return true;
If you want strings that do not exist in your map to be sorted before that do.
Try declaring your comparison method to be const and to use const references for the arguements. The first fix is to ensure that you can call your method with constant versions of your OrderComarator the second fix is to avoid copying.
bool operator()( const string& lhs, const string& rhs ) const {
I am trying to add a pair<int,int> to a set. If a pair shares the same two values as another in the set, it should not be inserted.
Here's my non-working code:
typedef std::pair<int, int> PairInt;
template<>
bool std::operator==(const PairInt& l, const PairInt& r)
{
return (l.first == r.first && l.second == r.second) ||
(l.first == r.second && l.second == r.first);
}
int main()
{
std::set<PairInt> intSet;
intSet.insert(PairInt(1,3));
intSet.insert(PairInt(1,4));
intSet.insert(PairInt(1,4));
intSet.insert(PairInt(4,1));
}
At the moment, the (4,1) pair gets added even though there is already a (1,4) pair. The final contents of the set are:
(1 3)
(1 4)
(4 1)
and I want it to be
(1 3)
(1 4)
I've tried putting breakpoints in the overloaded method, but they never get reached. What have I done wrong?
Sets are based on operator< (an ordering/equivalence relationship), not operator== (which is an equality relationship).
To do the thing that you are trying to do, use a custom comparator:
#include <set>
#include <utility>
#include <cassert>
typedef std::pair<int, int> PairInt;
PairInt normalize(const PairInt& p) {
return p.second < p.first ? PairInt(p.second, p.first) : p;
}
struct Comparator {
bool operator()(const PairInt& l, const PairInt& r) const {
//Compare canonical forms of l and r.
return normalize(l) < normalize(r);
}
};
int main()
{
std::set<PairInt, Comparator> intSet;
intSet.insert(PairInt(1,3));
intSet.insert(PairInt(1,4));
intSet.insert(PairInt(1,4));
intSet.insert(PairInt(4,1));
assert(intSet.size() == 2);
}
You will need to provide a comparison function for seeing of one item is less than the other, not for determining if they are equal. Here is a complete example:
#include <utility>
#include <algorithm>
#include <set>
#include <iostream>
typedef std::pair<int, int> PairInt;
typedef bool Compare(const PairInt &,const PairInt &);
bool compare(const PairInt &l,const PairInt &r)
{
int lfirst = std::min(l.first,l.second);
int rfirst = std::min(r.first,r.second);
if (lfirst<rfirst) return true;
if (rfirst<lfirst) return false;
return std::max(l.first,l.second)<std::max(r.first,r.second);
}
int main()
{
typedef std::set<PairInt,Compare*> IntSet;
IntSet intSet(compare);
intSet.insert(PairInt(1,3));
intSet.insert(PairInt(1,4));
intSet.insert(PairInt(1,4));
intSet.insert(PairInt(4,1));
for (IntSet::const_iterator i=intSet.begin(); i!=intSet.end(); ++i) {
std::cerr << i->first << "," << i->second << "\n";
}
}
Output:
1,3
1,4
The compare should determine if first item is less than the second item. So it should be like this:
namspace std
{
template<>
bool operator < (const PairInt& l, const PairInt& r)
{
//swap only if they're unequal to avoid infinite recursion
if (l.first != l.second)
{
//swap elements, considering your special case
if (l.first == r.second && l.second == r.first)
return l < PairInt(r.second, r.first); //call again!
}
//actual comparison is done here
if ( l.first != r.first )
return l.first < r.first;
else
return l.second < r.second;
}
}
Now it gives the desired output:
1,3
1,4
Have a look at the online demo.
Note that the compare function follows : Strict weak ordering