【问题标题】:STL containers and algorithm C++STL 容器和算法 C++
【发布时间】:2015-11-24 22:59:51
【问题描述】:

我被一个问题难住了一段时间。在将文本文件输入地图容器之前,我似乎无法检查包含一组排除单词的文本文件。我尝试了很多事情,但似乎无法解决它。我是 C++ 新手,刚开始学习 STL 和容器。

using namespace std;
//checking I know is wrong but I do not know how to compare the pair with the set.

bool checking(pair<string, int> const & a, set<string> const &b) {
    return a.first != b;
}

void print(pair<string, int> const & a) {cout << a.first << "  " << a.second << endl;}

int main() {

    ifstream in("document.txt");
    ifstream exW("excluded.txt");

    map<string, int> M;
    set<string> words;

    copy(istream_iterator<string>(exW),
         istream_iterator<string>(),
         inserter(words, begin(words)));

    //Need to exlclude certain words before copying into a Map
    // CAN NOT USE FOR LOOP
    //I cant seem to get the predicate right.
    copy_if(istream_iterator<string>(in),
            istream_iterator<string>(),
    [&](const string & s) { M[s]++;},
    checking);

    for_each(begin(M),
             end(M),
             [](pair<string, int> const & a) 
             {
                 cout << a.first << "  " <<  a.second << endl;
             }
    );

    return 0;
}

任何提示或建议都很棒!

【问题讨论】:

  • 您到底想达到什么目的?您不能将字符串与集合“比较”,它们完全代表不同的概念。您是否尝试查看该字符串是否属于该集合?
  • @vsoftco 我正在尝试读取 sample.txt 和 copy_if 不排除单词到地图容器中。
  • 如果你想复制字符串,copy_if谓词需要返回true,如果不是false

标签: c++ c++11 stl containers


【解决方案1】:

我会这样做,使用 lambda 表达式作为您的测试,这样可以帮助您开始:

#include <set>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <iterator>

using namespace std;

int main() 
{
    ifstream in("document.txt");
    ifstream exW("excluded.txt");

    set<string> words{istream_iterator<string>(exW),{}}; // here we store the excluded words

    copy_if(istream_iterator<string>(in),
            istream_iterator<string>(), // can also use just {} instead
            ostream_iterator<string>(std::cout," "), // output to std::cout
            [&words](const std::string& word) // this is how the predicate should look
            {
                return words.find(word) == words.end(); // true if not found
            }
            );
}

注意我在std::copy_if中直接输出到std::cout。您当然可以在某个容器中使用迭代器(例如您的 std::map)。另请注意,谓词将std::string 作为输入(这是您验证的内容)并检查它是否属于排除词的std::set,返回boolwords 还需要在 lambda 中捕获。我通过引用捕获它,这样您就不会得到额外的副本。

【讨论】:

【解决方案2】:

如果您需要使用标准算法而不是循环,那么我可以建议使用标头 &lt;numeric&gt; 中声明的标准算法 std::accumulate

这是一个演示程序。而不是我使用字符串流的文件。

#include <iostream>
#include <set>
#include <map>
#include <string>
#include <sstream>
#include <numeric>
#include <iterator>

int main( void )
{
    std::istringstream exclude( "two four six" );
    std::set<std::string> words( ( std::istream_iterator<std::string>( exclude ) ),
                                 std::istream_iterator<std::string>() ); 

    for ( const auto &t : words ) std::cout << t << ' ';
    std::cout << std::endl;

    std::cout << std::endl;

    std::map<std::string, int> m;

    std::istringstream include( "one two three four five six five four one one" );

    std::accumulate( std::istream_iterator<std::string>( include ),
                     std::istream_iterator<std::string>(),
                     &m,
                     [&]( std::map<std::string, int> *acc, const std::string &t )
                     {
                         if ( !words.count( t ) ) ++( *acc )[t];
                         return acc;
                     } );

    for ( const auto &p : m ) std::cout << p.first << '\t' << p.second << std::endl;                     
}

程序输出是

four six two 

five    2
one 3
three   1

为了程序的可读性,可以将 lambda 定义放在算法调用之外。例如

auto add_if_not_in_set = [&]( std::map<std::string, int> *acc, const std::string &t )
{
    if ( !words.count( t ) ) ++( *acc )[t];
    return acc;
};

//...

std::accumulate( std::istream_iterator<std::string>( include ),
                 std::istream_iterator<std::string>(),
                 &m, add_if_not_in_set );

或者正如 @T.C. 指出的更简化的方法是使用标准算法std::for_each

例如

#include <iostream>
#include <set>
#include <map>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>

int main( void )
{
    std::istringstream exclude( "two four six" );
    std::set<std::string> words( ( std::istream_iterator<std::string>( exclude ) ),
                                 std::istream_iterator<std::string>() ); 

    for ( const auto &t : words ) std::cout << t << ' ';
    std::cout << std::endl;

    std::cout << std::endl;

    std::map<std::string, int> m;


    std::istringstream include( "one two three four five six five four one one" );

    std::for_each( std::istream_iterator<std::string>( include ),
                   std::istream_iterator<std::string>(),
                   [&m, &words]( const std::string &s )
                   {
                       if ( !words.count( s ) ) ++m[s];
                   } );

    for ( const auto &p : m ) std::cout << p.first << '\t' << p.second << std::endl;                     
}

通常可以使用不同的算法以多种方式完成相同的任务。:)

【讨论】:

  • 你为什么使用accumulate 并传递一个永远不会改变的累加器? std::for_each( std::istream_iterator&lt;std::string&gt;( include ), std::istream_iterator&lt;std::string&gt;(), [&amp;]( const std::string &amp;t ) { if ( !words.count( t ) ) ++m[t]; } ); 更短,可以说更容易理解。
  • @T.C.我没有使用 std::for_each 因为我认为它与基于范围的 for 循环相同。:) 所以我想到了一些其他算法。:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-03
  • 1970-01-01
  • 2011-02-07
  • 2012-03-08
  • 2014-06-17
  • 2012-08-10
  • 1970-01-01
相关资源
最近更新 更多