【问题标题】:Incrementing word count from a stringstream从字符串流中增加字数
【发布时间】:2013-10-18 20:56:26
【问题描述】:

我还在学习 C++,但我想出了一个很难理解的表达方式。

基本上它将 cin 输入到 istringstream,然后对其进行处理以保留单个单词,并在地图容器“单词”中计数(出现的次数)

代码

std::map<string, int> words;

std::istream_iterator<string> begin(cin); 
std::istream_iterator<string> end;

while(begin != end ) 
   words[*begin++]++;

如果有人可以为我解释一下 while 循环的代码?我知道最终结果,只是想知道它是如何做到的。谢谢!

【问题讨论】:

  • 如果您不知道 istream_iterator 是什么(并且为您所做),或者不知道 std::map&lt;&gt;operator [] 的默认插入是如何发生的,说明单个表达式可能需要一会儿。请参阅 this for istream_iteratorthis for std::map::operator []。如果不是很明显,那条小线中有大量功能。

标签: c++


【解决方案1】:

关于std::istream_iterator&lt;T&gt;这种类型提供了一个迭代器接口来流式输入/输出。这里,beginend 是迭代器(您可以将它们视为strings 的“虚拟”容器中的迭代器,在cin 的输入中表示)。

因为begin 是用cin 初始化的,所以它将成为我所说的“活动”迭代器:它将在第一次取消引用时从cin 读取(如*begin),并且第一次在每次前增量或后增量后被推迟 (begin++)。

因为end 没有用任何东西初始化,所以它变成了一个特殊的“结束标记”迭代器,而不是一个活动的迭代器。这个特殊迭代器值的唯一目的是成为活动迭代器在到达文件末尾时可以比较的值。

这样,从文件中读取一系列T(在本例中为string)可以硬塞进一个普通的容器迭代器遍历中:)

[编辑:operator[]() 的澄清行为。]

关于std::map&lt;string, int&gt;:,您可以将映射视为一种非常通用的数组类型,它可以被小整数以外的事物索引——在本例中是字符串。 std::map&lt;K, T&gt; 类型重载 operator[]() 以返回对由 key 参数标识的现有元素的引用,并具有附加(通常很有帮助,因为它在这里)功能,如果地图中不存在具有该键的元素,它将添加默认值(int 为 0)并返回对这个全新元素的引用。

【讨论】:

  • 谢谢,但我不是指循环的条件,当我在里面说时,我的错!无论如何谢谢!我了解条件和迭代器,只是下面的代码令人困惑
  • @user2896358:啊 :) 我已经添加了一些关于地图如何工作的内容。有趣的是,我认为这是更明显的部分:-P
  • +1 @user2896358 关于此答案中的最后一句话,当通过 operator[] 访问密钥并且没有匹配的条目时。创建一个新的,并通过Type() 的值初始化添加映射的值类型(第二个模板参数)(注意括号)。在这种情况下,这意味着int()。按照 C++ 标准,一个整数值初始化变成了零初始化,即初始整数为 0;正是您第一次进入新条目时想要的。 C++11 8.5, sec 10,7,5 详细介绍了这一点。
  • 啊,是的!下标运算符!因此,如果键存在,它会返回一个引用,否则它会使用默认值添加它。我要去某个地方吗?谢谢! :D
  • @user2896358 是的,你明白它是如何工作的;无论哪种方式,您都会返回对映射中值条目的引用。它要么被添加,要么已经存在。从技术上讲,您可以(并且应该)这样做:++words[*begin++];(并查看此答案的内容长度,以及我在上面的一般性评论中所说的话。那个小声明中有很多内容,并且解释它不是t 完全是微不足道的)。
【解决方案2】:
  1. *开始 - 获取迭代器值
  2. *begin++ - 然后递增迭代器
  3. words[*begin++] - 将步骤 1 中的值传递给 map [] 运算符,这意味着通过键获取值。
  4. words[*begin++]++ - 递增该值。

对于来自 cin 的所有字符串,我们在 map 中搜索一个 int 并递增它。好像我们计算相等的字符串。

【讨论】:

    【解决方案3】:

    如果您无法理解压缩的单行,只需将其分解为多行并保存中间结果即可。

    std::map<std::string, int> words;
    
    std::istream_iterator<std::string> begin(std::cin); 
    //default constructor creates an end of stream iterator
    std::istream_iterator<std::string> end_of_stream; 
    
    while(begin != end_of_stream ){
        std::string from_cin = *begin;     //reads from std::cin 
        int &count_ref = words[from_cin];  //can create a new entry 
        count_ref++;                       //increment value in the map
        begin++;                           //advance the stream_iterator
    }
    

    用于参考确切语义的相关页面是

    isstream_iterator constructor

    isstream_iterator operator *

    map operator []

    【讨论】:

    • 这实际上是一个相当准确的细分。
    【解决方案4】:

    std::map 中的下标运算符的行为方式如下。如果没有与键对应的元素,则创建它并初始化为零。否则返回值类型的引用。

    所以在你的代码表达式中

    words[*begin++]
    

    返回 value_type 类型的现有值,它对应于等于 *begin 的字符串对象或 0,因为新对象是使用键 *begin 创建的。之后返回值递增。

    words[*begin++]++;
    

    也许简单引用 C++ 标准会更好

    T& 运算符[](const key_type& x); 1 效果:如果没有钥匙 相当于映射中的 x,将 value_type(x, T()) 插入映射中。 2 要求:key_type 应为 CopyConstructible 和 mapped_type 应 是 DefaultConstructible。 3 返回:对 mapped_type 的引用 对应于 *this 中的 x。 4 复杂度:对数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-09
      • 1970-01-01
      • 1970-01-01
      • 2013-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多