1 /* Boost.MultiIndex example of use of hashed indices.
2  *
3  * Copyright 2003-2008 Joaquin M Lopez Munoz.
4  * Distributed under the Boost Software License, Version 1.0.
5  * (See accompanying file LICENSE_1_0.txt or copy at
6  * http://www.boost.org/LICENSE_1_0.txt)
7  *
8  * See http://www.boost.org/libs/multi_index for library home page.
9  */
10 
11 #if !defined(NDEBUG)
12 #define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
13 #define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
14 #endif
15 
16 #include <boost/multi_index_container.hpp>
17 #include <boost/multi_index/hashed_index.hpp>
18 #include <boost/multi_index/member.hpp>
19 #include <boost/multi_index/ordered_index.hpp>
20 #include <boost/tokenizer.hpp>
21 #include <iomanip>
22 #include <iostream>
23 #include <string>
24 
25 using boost::multi_index_container;
26 using namespace boost::multi_index;
27 
28 /* word_counter keeps the ocurrences of words inserted. A hashed
29  * index allows for fast checking of preexisting entries.
30  */
31 
32 struct word_counter_entry
33 {
34   std::string  word;
35   unsigned int occurrences;
36 
word_counter_entryword_counter_entry37   word_counter_entry(std::string word_):word(word_),occurrences(0){}
38 };
39 
40 /* see Compiler specifics: Use of member_offset for info on
41  * BOOST_MULTI_INDEX_MEMBER
42  */
43 
44 typedef multi_index_container<
45   word_counter_entry,
46   indexed_by<
47     ordered_non_unique<
48       BOOST_MULTI_INDEX_MEMBER(word_counter_entry,unsigned int,occurrences),
49       std::greater<unsigned int> /* sorted beginning with most frequent */
50     >,
51     hashed_unique<
52       BOOST_MULTI_INDEX_MEMBER(word_counter_entry,std::string,word)
53     >
54   >
55 > word_counter;
56 
57 /* utilities */
58 
59 template<typename T>
60 struct increment
61 {
operator ()increment62   void operator()(T& x)const{++x;}
63 };
64 
65 typedef boost::tokenizer<boost::char_separator<char> > text_tokenizer;
66 
main()67 int main()
68 {
69   /* boostinspect:noascii */
70 
71   std::string text=
72     "En un lugar de la Mancha, de cuyo nombre no quiero acordarme, no ha "
73     "mucho tiempo que viv�a un hidalgo de los de lanza en astillero, adarga "
74     "antigua, roc�n flaco y galgo corredor. Una olla de algo m�s vaca que "
75     "carnero, salpic�n las m�s noches, duelos y quebrantos los s�bados, "
76     "lantejas los viernes, alg�n palomino de a�adidura los domingos, "
77     "consum�an las tres partes de su hacienda. El resto della conclu�an sayo "
78     "de velarte, calzas de velludo para las fiestas, con sus pantuflos de lo "
79     "mesmo, y los d�as de entresemana se honraba con su vellor� de lo m�s "
80     "fino. Ten�a en su casa una ama que pasaba de los cuarenta, y una "
81     "sobrina que no llegaba a los veinte, y un mozo de campo y plaza, que "
82     "as� ensillaba el roc�n como tomaba la podadera. Frisaba la edad de "
83     "nuestro hidalgo con los cincuenta a�os; era de complexi�n recia, seco "
84     "de carnes, enjuto de rostro, gran madrugador y amigo de la caza. "
85     "Quieren decir que ten�a el sobrenombre de Quijada, o Quesada, que en "
86     "esto hay alguna diferencia en los autores que deste caso escriben; "
87     "aunque, por conjeturas veros�miles, se deja entender que se llamaba "
88     "Quejana. Pero esto importa poco a nuestro cuento; basta que en la "
89     "narraci�n d�l no se salga un punto de la verdad.";
90 
91   /* feed the text into the container */
92 
93   word_counter   wc;
94   text_tokenizer tok(text,boost::char_separator<char>(" \t\n.,;:!?'\"-"));
95   unsigned int   total_occurrences=0;
96   for(text_tokenizer::iterator it=tok.begin(),it_end=tok.end();
97       it!=it_end;++it){
98     /* Insert the word into the container. If duplicate, wit will point to
99      * the preexistent entry.
100      */
101 
102     ++total_occurrences;
103     word_counter::iterator wit=wc.insert(*it).first;
104 
105     /* Increment occurrences.
106      * In a lambda-capable compiler, this can be written as:
107      *   wc.modify_key(wit,++_1);
108      */
109 
110     wc.modify_key(wit,increment<unsigned int>());
111   }
112 
113   /* list words by frequency of appearance */
114 
115   std::cout<<std::fixed<<std::setprecision(2);
116   for(word_counter::iterator wit=wc.begin(),wit_end=wc.end();
117       wit!=wit_end;++wit){
118     std::cout<<std::setw(11)<<wit->word<<": "
119              <<std::setw(5) <<100.0*wit->occurrences/total_occurrences<<"%"
120              <<std::endl;
121   }
122 
123   return 0;
124 }
125