find_if algorithm on multimaps

D

devel

Hello,
Could someone tell me why the find_if statement applied to my multimap
dictionnary is doesn't compile? Does this algorithm doesn't work on a
multimap?

I don't understand why the adjacent_find compile and not the find_if
statement?

By the way my first intention was to write:
find_if (j, dictionnary.end(), bind1st (not_equal_to <string> (), *j));
but it doesn't compile neither for the same reason I guess.

Thanks by advance,
devel.

#include <iostream>
#include <map>
#include <fstream>
#include <iterator>
#include <string>
#include <vector>
#include <functional>

using namespace std;

typedef multimap<string, string, less <string> > MapDictionnary;

int
main (int argc, char **argv)
{
string dictionnaryName;
cout << "Enter dictionnary name :";
cin >> dictionnaryName;

MapDictionnary dictionnary;
ifstream dictionnaryIFStream (dictionnaryName.c_str());
istream_iterator<string> it;
for (it=istream_iterator<string> (dictionnaryIFStream);
it!=istream_iterator<string> (); ++it)
{
vector<char> sortedString ((*it).begin(), (*it).end());
sort (sortedString.begin(), sortedString.end());
dictionnary.insert (make_pair<string, string>
(string(sortedString.begin(), sortedString.end()), (*it)));
}

cout << "The dictionnary " << dictionnaryName << " contains " <<
dictionnary.size() << " words." << endl;

MapDictionnary::iterator j=dictionnary.begin();
MapDictionnary::iterator k;
while (true)
{
j=adjacent_find (j, dictionnary.end(), dictionnary.value_comp());
if (j==dictionnary.end())
break;

// INCORECT FIND_IF STATEMENT !! k=find_if (j, dictionnary.end(),
dictionnary.value_comp());
// End of : INCORECT FIND_IF STATEMENT !!
};

return 0;
}
 
D

devel

devel said:
Hello,
Could someone tell me why the find_if statement applied to my multimap
dictionnary is doesn't compile? Does this algorithm doesn't work on a
multimap?

I don't understand why the adjacent_find compile and not the find_if
statement?

By the way my first intention was to write:
find_if (j, dictionnary.end(), bind1st (not_equal_to <string> (), *j));
but it doesn't compile neither for the same reason I guess.

Thanks by advance,
devel.

#include <iostream>
#include <map>
#include <fstream>
#include <iterator>
#include <string>
#include <vector>
#include <functional>

using namespace std;

typedef multimap<string, string, less <string> > MapDictionnary;

int
main (int argc, char **argv)
{
string dictionnaryName;
cout << "Enter dictionnary name :";
cin >> dictionnaryName;

MapDictionnary dictionnary;
ifstream dictionnaryIFStream (dictionnaryName.c_str());
istream_iterator<string> it;
for (it=istream_iterator<string> (dictionnaryIFStream);
it!=istream_iterator<string> (); ++it)
{
vector<char> sortedString ((*it).begin(), (*it).end());
sort (sortedString.begin(), sortedString.end());
dictionnary.insert (make_pair<string, string>
(string(sortedString.begin(), sortedString.end()), (*it)));
}

cout << "The dictionnary " << dictionnaryName << " contains " <<
dictionnary.size() << " words." << endl;

MapDictionnary::iterator j=dictionnary.begin();
MapDictionnary::iterator k;
while (true)
{
j=adjacent_find (j, dictionnary.end(), dictionnary.value_comp());
if (j==dictionnary.end())
break;

// INCORECT FIND_IF STATEMENT !! k=find_if (j,
dictionnary.end(), dictionnary.value_comp());
// End of : INCORECT FIND_IF STATEMENT !!
};

return 0;
}

Ok, I see my mistake find_if takes an unary predicate.
My question is why
k=find_if (j, dictionnary.end(), bind1st (not_equal_to <string> (),
(*j).first));

doesn't work?

Thanks by advance,
devel.

PS: The compiler output is:

/usr/lib/gcc/i386-redhat-linux/3.4.4/../../../../include/c++/3.4.4/bits/stl_algo.h:
In function `_InputIterator std::find_if(_InputIterator, _InputIterator,
_Predicate, std::input_iterator_tag) [with _InputIterator =
std::_Rb_tree_iterator<std::pair<const std::string, std::string> >,
_Predicate = std::binder1st<std::not_equal_to<std::string> >]':
/usr/lib/gcc/i386-redhat-linux/3.4.4/../../../../include/c++/3.4.4/bits/stl_algo.h:336:
instantiated from `_InputIterator std::find_if(_InputIterator,
_InputIterator, _Predicate) [with _InputIterator =
std::_Rb_tree_iterator<std::pair<const std::string, std::string> >,
_Predicate = std::binder1st<std::not_equal_to<std::string> >]'
stl_tut_ref_guide_chap13.cc:40: instantiated from here
/usr/lib/gcc/i386-redhat-linux/3.4.4/../../../../include/c++/3.4.4/bits/stl_algo.h:187:
erreur: pas de concordance pour l'appel de «
(std::binder1st<std::not_equal_to<std::string> >) (std::pair<const
std::string, std::string>&) »
/usr/lib/gcc/i386-redhat-linux/3.4.4/../../../../include/c++/3.4.4/bits/stl_function.h:406:
note: candidats sont: typename _Operation::result_type
std::binder1st<_Operation>::eek:perator()(const typename
_Operation::second_argument_type&) const [with _Operation =
std::not_equal_to<std::string>]
/usr/lib/gcc/i386-redhat-linux/3.4.4/../../../../include/c++/3.4.4/bits/stl_function.h:412:
note: typename _Operation::result_type
std::binder1st<_Operation>::eek:perator()(typename
_Operation::second_argument_type&) const [with _Operation =
std::not_equal_to<std::string>]
 
M

Maxim Yegorushkin

devel said:
Ok, I see my mistake find_if takes an unary predicate.
My question is why
k=find_if (j, dictionnary.end(), bind1st (not_equal_to <string> (),
(*j).first));

doesn't work?

Dereferencing your iterator yields pair<string const, string>. There is
no compare operators declared for the pair and the string needed. Roll
out your own predicate object or use boost::bind/lambda.
 
D

Daniel T.

devel said:
Hello,
Could someone tell me why the find_if statement applied to my multimap
dictionnary is doesn't compile? Does this algorithm doesn't work on a
multimap?

I don't understand why the adjacent_find compile and not the find_if
statement?

By the way my first intention was to write:
find_if (j, dictionnary.end(), bind1st (not_equal_to <string> (), *j));
but it doesn't compile neither for the same reason I guess.

Thanks by advance,
devel.

#include <iostream>
#include <map>
#include <fstream>
#include <iterator>
#include <string>
#include <vector>
#include <functional>

using namespace std;

typedef multimap<string, string, less <string> > MapDictionnary;

int
main (int argc, char **argv)
{
string dictionnaryName;
cout << "Enter dictionnary name :";
cin >> dictionnaryName;

MapDictionnary dictionnary;
ifstream dictionnaryIFStream (dictionnaryName.c_str());
istream_iterator<string> it;
for (it=istream_iterator<string> (dictionnaryIFStream);
it!=istream_iterator<string> (); ++it)
{
vector<char> sortedString ((*it).begin(), (*it).end());
sort (sortedString.begin(), sortedString.end());
dictionnary.insert (make_pair<string, string>
(string(sortedString.begin(), sortedString.end()), (*it)));

}

cout << "The dictionnary " << dictionnaryName << " contains " <<
dictionnary.size() << " words." << endl;

MapDictionnary::iterator j=dictionnary.begin();
MapDictionnary::iterator k;
while (true)
{
j=adjacent_find (j, dictionnary.end(), dictionnary.value_comp());

The only way 'j' will *not* equal 'end()' is if the same word is in the
file without any intervening words that use the same letters. For
example, if the file contained "time mite emit time mite emit", 'j'
would equal end(). Is this really what you want?

if (j==dictionnary.end())
break;

// INCORECT FIND_IF STATEMENT !! k=find_if (j, dictionnary.end(),
dictionnary.value_comp());
// End of : INCORECT FIND_IF STATEMENT !!
};

return 0;
}

(By this point, your function is way to long and trying to do too much.
Was this just for example purposes?)

If you are trying to stop duplicate entries then a different structure
may be called for:
----------------------------------------------------------------------
typedef map< string, set<string> > MapDict;

void extractWords( istream& is, MapDict& dict ) {
istream_iterator<string> it( is );
while ( it != istream_iterator<string>() ) {
string entry( *it );
sort( entry.begin(), entry.end() );
dict[entry].insert( *it );
++it;
}
}

int main() {
cout << "Enter file name: ";
string name;
cin >> name;
MapDict dict;
extractWords( ifstream( name ), dict );
// use dict here
}
----------------------------------------------------------------------
'std::set' will automatically remove duplicates, and sort the entries.

If you really want it in a multimap, then after applying the above you
can:
----------------------------------------------------------------------
int main() {
cout << "Enter file name: ";
string name;
cin >> name;
MapDict dict;
ifstream file( name );
extractWords( file, dict );
multimap< string, string > expandedDict;
for ( MapDict::iterator it = dict.begin(); it != dict.end(); ++it )
for ( set<string>::iterator it2 = it->second.begin();
it2 != it->second.end(); ++it2 )
expandedDict.insert( make_pair( it->first, *it2 ) );
// use expandedDict
}
----------------------------------------------------------------------

If it must be a multimap from the beginning, then you should make your
check for duplicates before the insert, because trying to remove
duplicates after the fact would be really hairy.

----------------------------------------------------------------------
typedef multimap< string, string > MapDict;

// with just a little work, this can be made much more general...
// I leave that as an exorcise. :)
struct second_is : unary_function< string, bool > {
string value;
second_is( string v ): value( v ) { }
bool operator()( MapDict::value_type v ) const {
return v.second == value;
}
};

void extractWords( istream& is, MapDict& dict ) {
istream_iterator<string> it( is );
while ( it != istream_iterator<string>() ) {
string entry( *it );
sort( entry.begin(), entry.end() );
pair< MapDict::iterator, MapDict::iterator > range =
dict.equal_range( entry );
if ( find_if( range.first, range.second, second_is( *it ) ) ==
range.second )
dict.insert( make_pair( entry, *it ) );
++it;
}
}
----------------------------------------------------------------------
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,044
Latest member
RonaldNen

Latest Threads

Top