【问题标题】:Word value into a key map which has set value将单词值转换为具有设定值的键映射
【发布时间】:2023-03-27 13:27:02
【问题描述】:

我知道map 是什么以及它的一般基本功能,但我不知道为什么在这里使用set 而不是仅仅声明int i = value 或类似的东西。

我真正想做的是:将单词放入向量后,我还想将同一个单词用作值的键。但我真的不知道使用map 这样做的全部目的。不确定我是否提供了足够的信息,但只是询问您还需要什么,我会回复。

我只提供了一个readWords 函数,但是如果有人需要完整的代码,包括头文件、类和主文件,那么我也可以把它们放上来。

在帮助下,我在那里写下了部分代码,但老实说,我不知道在 push_back() 函数之后它在做什么。

/* Read word-by-word from filename and store words in text vector.
* Also use normalized version of word as key in concordance map
* The value associated with each key in the map is a set whose
* keys are the associated indices into the vector.
*/
void Concordance::readWords(char * filename){
    ifstream fin(filename, ifstream::in);
    if (fin.is_open()){
        while(!fin.eof()){
            string word;
            fin >> word;
            normalize(word);
            text.push_back(word); //puts word into vector

            set<int> seat;
            seat.insert(text.size()-1);
            pair<string, set<int> > pear;
            concordance.insert(pear);

        }
    }
    else{
        cerr << "Unable to open file datafile.txt";
        exit(1);   // call system to stop
    }
    fin.close(); //closes the filename
}

【问题讨论】:

    标签: c++ stl map set


    【解决方案1】:

    我认为您并不完全了解此算法的要求。 (顺便问一下,这是作业吗?)

    这里的目标是产生一个索引 - 每个单词的所有出现的列表。 set 的要点是保存所有出现的。 (例如:单词“apple”可能出现在第 1、73 和 100 页。因此“apple”的映射条目必须包含所有这些值。)

    规范化的目的是为了节省阅读时间的读者:“apple”、“Apple”和“apples”可能都应该在地图的一个条目中。

    了解这一点,我们可以更新您的程序。

    首先,在读取数据之前,永远不要检查eof。只有在读取数据后检查它才有意义。事实上,这个检查有一个更简单的习语:

    string word;
    while (fin >> word) {
        ...
    

    在我看来,我们需要将 original 单词存储在向量中,然后使用 normalized 单词作为地图索引

    text.push_back(word);
    normalize(word);
    

    现在,更新地图很容易。您不需要pair,只需使用[] 运算符。意识到仅仅引用一个映射条目就会让它出现!

    concordance[word].insert(text.size()-1);
    

    编辑将最后一点分开:

    concordance[word] 在地图中查找由word 索引的条目。如果条目存在,则返回。如果条目没有退出,则创建它,并返回新形成的条目。 .insert 是对由word 索引的映射条目定位的集合的插入操作。 text.size()-1 是插入到位于由word 索引的映射条目的集合中的值。

    将其重新组合在一起,concordance[word].insert(text.size()-1) 查看地图,检索(或创建)指示的 set,然后将数字 text.size()-1 插入该集合。

    你去!

    【讨论】:

    • 所以一致[word].insert(text.size()-1);将“单词”插入索引地图,然后插入文本大小?我也不需要声明一个新集合?
    • 是的,concordance[word].insert(text.size()-1); 正在将word 插入到索引映射中,然后将text.size()-1 插入到集合中。您不需要声明新集合。
    • 感谢您的详尽解释!如果可以的话,我会投票给你。 :D
    【解决方案2】:

    不知道你是不是在复制代码时犯了错误,或者代码是不是故意这样,但是seat这个集合没有被使用(除了插入一个元素,但是因为它没有被读取/stored 会丢失),所有添加到concordance 的元素都会成对("",[empty set])

    它看起来不像是在尝试建立索引,即从单词到单词出现的向量中的位置的映射。如果是这样的话,这样做可能会更好:

    std::map<std::string, std::set<int> > concordance;
    //...
    concordance[word].insert(text.size()-1); // if it does not exists, it will create it
                                             // if it exists it will retrieve it and
                                             // add the new position
    

    这种模式通常用于将单词索引到页面中(例如对于一本书),其中集合比向量具有优势,它可以保证唯一性,如果一个单词在单个页面中出现 100 次,则集合将确保不重复页码(您必须在向量中进行测试)。这不是代码的情况,因为索引是单词向量中的位置,它们本身是唯一的。

    还请注意,正如 Nawaz 指出的那样,循环需要进行一些更正。

    【讨论】:

      【解决方案3】:

      首先,您的while 循环是错误的,因为eof 标志(或任何其他失败标志)被设置 尝试从流中读取失败;这意味着,如果尝试读取失败,您尝试将先前读取的word 插入向量两次,循环中的其余代码仍然执行,而实际上它不应该执行。

      一个更惯用的while循环是这样的:

      string word;
      while( fin >> word ){
         normalize(word);
         text.push_back(word); //puts word into vector
      
         set<int> seat;
         seat.insert(text.size()-1);
         pair<string, set<int> > pear;
         concordance.insert(pear);
      }
      

      如果尝试读取(即fin &gt;&gt; word)失败,则返回的std::istream&amp; 隐式转换为false,并退出循环。

      我并没有清楚地理解你帖子的其余部分、问题以及你到底想做什么,所以我无法对此发表评论。

      【讨论】:

        猜你喜欢
        • 2018-07-23
        • 1970-01-01
        • 2016-02-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多