Is there any way that you could possible use map.find() / map.count() algorithms for a key, which is of type object of a class?
My multimap is made of pairs - map.<myClass, enum>
and myClass has some member, like Filename for example. I would like to search for duplicate Filenames in my map and I have read that find() and count() functions do that for keys, but is possible to implement them to search for a member of the key?
Here is some code:
CDirectory (string n) {
fp.open (n, ios::in);
string dirName, fileName, fType;
int fileSize;
fp >> dirName;
m_strDirectory = dirName;
while (fp >> fileName >> fileSize >> fType) {
CFile obj (fileName, fileSize);
if (fType == "Archive")
filetype = Filetype::Archive;
else if (fType == "Hidden")
filetype = Filetype::Hidden;
else if (fType == "ReadOnly")
filetype = Filetype::ReadOnly;
else if (fType == "System")
filetype = Filetype::System;
else
filetype = Filetype::FileNotSupported;
m_DirectoryMap.insert(pair<CFile, Filetype>(CFile(obj.getFileName(), obj.getFileSize()), Filetype(filetype)));
}
multimap<CFile, Filetype>::iterator p = m_DirectoryMap.begin();
while ( p != m_DirectoryMap.end()) {
cout << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
++p;
}
}
This is the constructor of the second class, which has a multimap of pairs (Objects of another class, enum>).
And here is the first class:
class CFile {
string m_strFile;
unsigned int m_size;
public:
CFile () { m_strFile = ""; m_size = 0; }
CFile (string name, int size ) { m_strFile = name; m_size = size; }
string getFileName () const { return m_strFile; }
int getFileSize () const { return m_size; }
void setFileSize ( int size ) { m_size = size; }
bool operator< (CFile& obj) {
return ( m_size < obj.m_size );
}
bool operator== (const CFile& obj) {
return ( m_size == obj.m_size );
}
friend ostream& operator<< ( ostream& ost, const CFile& obj ) {
return ost << obj.m_strFile << obj.m_size;
}
friend istream& operator>> ( istream& ist, CFile& obj ) {
return ist >> obj.m_strFile >> obj.m_size;
}
static bool Greater(const CFile& obj1, const CFile& obj2) {
if ( obj1.m_size > obj2.m_size )
return true;
else
return false;
}
};
I want to find duplicates of string m_strFile
;
A std::multimap
compares keys through a Predicate
(a function object whose call operator takes a reference to two objects of type Key
).
The default predicate for a std::multimap
is std::less<>
, which is why maps are normally ordered by ascending key.
In order to make your keys comparable, you either need to specify a custom predicate in the map's template argument list (in the third position), or give your class a <
operator.
Then you would iterate through the map in groups of pairs, such as:
struct MyKey
{
MyKey(std::string fname) : _filename { std::move(fname) } {}
const std::string& filename() const { return _filename; }
private:
std::string _filename;
};
// define a predicate to order the map
struct order_by_filename {
bool operator()(const MyKey& l, const MyKey& r) const {
return l.filename() < r.filename();
}
};
struct DataObject {};
std::multimap<MyKey, DataObject, order_by_filename> my_map;
void strip_duplicates()
{
for(auto current = my_map.begin() ; current != my_map.end() ; )
{
auto range = my_map.equal_range(current->first);
// range is a std::pair containing the first and last iterator
// of the range with equal keys
auto num_items = range.second - range.first;
if (num_items > 1) {
// strip duplicates
my_map.erase(std::next(range.first), range.second);
}
// move to next range of keys
current = range.second;
}
}
for completeness, here's another way eliminating duplicates without using equal_range
:
void erase_all_but_one(std::multimap<Key, Value>& mmap, const Key& to_erase)
{
auto ifind = mmap.find(to_erase);
if (ifind == mmap.end()) return;
for(ifind = std::next(ifind) ; ifind != mmap.end() && ifind->first == to_erase ; )
{
// NOTE: take a copy of the advanced iterator BEFORE erasing
// the iterator.
auto inext = std::next(ifind);
mmap.erase(ifind);
ifind = inext;
}
}