Thread: adding objects to a unordered map:

  1. #1
    Registered User
    Join Date
    Jul 2013
    Location
    Germany
    Posts
    499

    adding objects to a unordered map:

    I am trying to solve some random puzzles so I do not lose/forget c++. I never used hashtables in C++ and decided I needed to brush up. I am having in creating a hashmap that holds objects with a string as a key:

    Code:
    #pragma once
    #include <iostream>
    #include <unordered_map>
    
    
    class WordCount
    {
    private:
    
    
    	struct Word{
    		int count;
    
    
    		int wordOccurrance(){
    			return count++;
    		}
    	}
    
    
    	std::unordered_map<std::string, Word> words; //error
    
    
    	std::unordered_map<std::string,std::string> mymap; //works fine
    public:
    	WordCount(void);
    	~WordCount(void);
    };

  2. #2
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Missing semicolon after struct Word.
    Empty functions do not need "void" in their parameter lists.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    You forgot the semi-colon to end the definition of the Word struct. That said, it seems to me that you do not need the Word struct because a std::unordered_map<std::string, int> will do.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    Registered User
    Join Date
    Jul 2013
    Location
    Germany
    Posts
    499
    Ahhhh..... Don't I look silly.....

    This what I am trying to do:

    1) Get occurrence of a word in a sentence, and count how many times that word occurred. For example if you were writing a ransom letter could you get all the words you need from a paragraph. I could do a loop but that would be O(n^2) but if I use a hashtable it would be O(Log N).

    Here is what I already did in Java:

    Code:
    package frequency;
    
    
    import java.util.Hashtable;
    
    
    
    
    public class CheckFrequency {
    
    
    	Hashtable<String, Word> words = new Hashtable<String, Word>();
    
    
    	class Word {
    		String word;
    		int counter=1;
    
    
    		Word(String word) {
    			this.word = word;
    		}
    
    
    		public void plusOne() {
    			counter++;	
    		}
    
    
    		String getWord(){
    			return word;
    		}
    	}
    
    
    	public void checkWords(String s) {
    
    
    		if (words.containsKey(s)) {
    			words.get(s).plusOne();
    		} else {
    			words.put(s, new Word(s));
    		}
    	}
    	
    	public void printFrequency(String s) {
    		
    		if(words.containsKey(s)) {
    			System.out.println(words.get(s).counter);
    			System.out.println(words.get(s).getWord());
    		}
    		else{
    			System.out.println("Word does not exist");
    		}
    		
    	}
    
    
    	public static void main(String[] args) {
    		
    		 String[] word = new String[4];
    		 word[0]="Drew";
    		 word[1]="Drew";
    		 word[2]="Drew"; 
    		 word[3]="Mike";
    		 
    		 CheckFrequency checker = new CheckFrequency();
    		 
    		 for(int i=0; i<4;i++){
    		 checker.checkWords(word[i]);
    		 }
    		 
    		checker.printFrequency("Drew"); 
    		 
    	}
    
    
    }
    I just playing around and finding little programs to learn how to use Hashtables a little better.

  5. #5
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Like laser said, std::unordered_map<std::string, int> will suffice. Why don't you give it a try? Btw, the lower bound should be O(N) because you can't iterate a string in less than linear time. Depending on the implementation of the hash map, the worst time could be as much as O(N^2) or O(N*logN).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by jocdrew21
    I could do a loop but that would be O(n^2) but if I use a hashtable it would be O(Log N).
    With a hash table it would be in O(n), not O(log n), because you need to process every word in the input. If you were using a balanced binary tree as is the typical implementation for std::map, then it would be in O(n log n) because the search operation for std::map is in O(log n).

    Quote Originally Posted by jocdrew21
    Here is what I already did in Java:
    You have the same unnecessary complication as in your C++ version: since you are already storing the word as a string in the key of the map, there is no need to also store it in a separate Word object, i.e., you can map words to their counts directly with the map.

    Speaking of map, since you are only using the Map interface, you might as well code to an interface by having words be a Map<String, Word> (or Map<String, Integer> if you take my previous suggestion).
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Jul 2013
    Location
    Germany
    Posts
    499
    With a hash table it would be in O(n), not O(log n), because you need to process every word in the input.
    You're right...

    Speaking of map, since you are only using the Map interface, you might as well code to an interface by having words be a Map<String, Word> (or Map<String, Integer> if you take my previous suggestion).
    I used the Word object because I was thinking the collisions would cause an issue. Meaning "Mike" and "Mike" have the same key and the countOccurrence function in the Word Struct would keep track that there are two objects named "Mike". However lets say "Alex" for whatever reason had the same key and was but in the same bucket. Now the bucket size will be 3, but really the value "mike" occurred twice.

    I thought it would be a easier way to store the values but it seems I am wrong.

    I will try to with a binary tree...

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by jocdrew21
    I used the Word object because I was thinking the collisions would cause an issue. Meaning "Mike" and "Mike" have the same key and the countOccurrence function in the Word Struct would keep track that there are two objects named "Mike". However lets say "Alex" for whatever reason had the same key and was but in the same bucket. Now the bucket size will be 3, but really the value "mike" occurred twice.
    std::unordered_map (and whatever hash table container you use in Java) will handle this collision resolution for you.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by jocdrew21 View Post
    I used the Word object because I was thinking the collisions would cause an issue. Meaning "Mike" and "Mike" have the same key and the countOccurrence function in the Word Struct would keep track that there are two objects named "Mike". However lets say "Alex" for whatever reason had the same key and was but in the same bucket. Now the bucket size will be 3, but really the value "mike" occurred twice.
    What kind of container wouldn't guarantee they all keys were unique? That would severely diminish its usability.
    Collision is an internal detail. You don't need to bother about it. You don't need to know how hash map works to use it. You only need to know the guarantees it provides.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #10
    Registered User
    Join Date
    Jul 2013
    Location
    Germany
    Posts
    499
    It is not working but this is what I have. If this what you were referring too. I am taking your advice, or at least attempting to. I am going to try the map<string,int> myMap approach after I get this way to work.

    Code:
    #include "WordCount.h"
    
    
    int main(void){
    
    
    	WordCount count;
    
    
    	std::string names[] = {"Drew","Mike","Alex","Drew","Mike"};
    
    
    	for(auto name: names){
    		count.checkWords(name);
    	}
    	
    	count.checkWords(names[0]);
    	
    	return 0;
    }
    Code:
    #pragma once
    #include <iostream>
    #include <map>
    
    
    class WordCount
    {
    private:
    
    
    	struct Word{
    		int count;
    
    
    		int wordOccurrance(){
    			return count++;
    		}
    	};
    
    
    	std::map<std::string, Word> words;
    
    
    public:
    	WordCount(void);
    	~WordCount(void);
    
    
    	void checkWords(std::string s);
    	void printFrequency(std::string s);
    };
    Code:
    #include "WordCount.h"
    #include <unordered_map>
    #include <string>
    
    
    WordCount::WordCount(void)
    {
    }
    
    
    WordCount::~WordCount(void)
    {
    }
    
    
    void WordCount::checkWords(std::string s){
    	
    		if(words.count(s)>0){
    
    
    			words.at(s).wordOccurrance;
    		}
    		else{
    			words.emplace (s,new Word);
    		}
    }
    
    
    void WordCount::printFrequency(std::string s){
    
    
    	if(words.at(s).wordOccurrance > 0){
    		int value = words.at(s).wordOccurrance;
    
    
    		std::cout<<"Word: "<<s<<" occurred "<<value<<" times.";
    	}else{
    		std::cout<<"The word does not exist.\n";
    	}
    
    
    }

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Stop using new. It is not required. Forget that it exists.
    Upon creating a new Word, you are not initializing its count.
    If the word already exists in the map, you are not increasing the count. Furthermore, you don't need to check if it exists. Check out map's operator [].
    Use const reference for all strings (that includes using const auto& in your loop). Copying strings can be expensive.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    Registered User
    Join Date
    Jul 2013
    Location
    Germany
    Posts
    499
    Got it to work!!! Thank you Elysia....

    Code:
    #include "WordCount.h"
    
    
    
    
    WordCount::WordCount()
    {
        
    }
    
    
    void WordCount::checkWords(std::string s){
        
        if(words.count(s)>0){
            
            words.at(s).wordOccurrance();
        }
        else{
            words[s];
        }
    }
    
    
    void WordCount::printFrequency(std::string s){
        
        if(words.at(s).wordOccurrance() >= 0){
            int value = words.at(s).wordOccurrance();
            
            std::cout<<"Word: "<<s<<" occurred "<<value<<" times.";
        }else{
            std::cout<<"The word does not exist.\n";
        }
        
    }
    Code:
    #include <iostream>
    #include <array>
    #include "WordCount.h"
    
    
    int main(int argc, const char * argv[]) {
        
        WordCount count;
        
        std::array<std::string, 5> names = {"Drew","Mike","Alex","Drew","Mike"};
        
        for (const auto& name: names) {
            
            count.checkWords(name);
        }
        
        count.printFrequency("Drew");
        
        return 0;}

  13. #13
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Your code is not correct. If a word appears once, its count will be 0, which means it will not be detected as having occurred.
    You need to insert and increment, which would be exactly the same as the case where it exists.
    Code:
    if (words.count(s) > 0)
        words.at(s).wordOccurrance();
    else
    {
        words[s];
        words[s].wordOccurrance();
    }
    ...which is equivalent to...
    Code:
    if (words.count(s) > 0)
        words.at(s).wordOccurrance();
    else
        words[s].wordOccurrance();
    ...which is equivalent to...
    Code:
    if (words.count(s) > 0)
        words[s].wordOccurrance();
    else
        words[s].wordOccurrance();
    ...which is equivalent to...
    Code:
    words[s].wordOccurrance();
    PrintFrequency and CheckWords should take the string by const reference.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  14. #14
    Registered User
    Join Date
    Jul 2013
    Location
    Germany
    Posts
    499
    You need to insert and increment, which would be exactly the same as the case where it exists.
    I handled that in the print function. Just to make sure I did what you said and I got an out of 2 for Alex when I know it is 1. I get one when way I have written it below:

    Code:
    void WordCount::printFrequency(std::string s){
        
        if(words.at(s).wordOccurrance() >= 0){
            int value = words.at(s).wordOccurrance();
            
            std::cout<<"Word: "<<s<<" occurred "<<value<<" times.";
        }else{
            std::cout<<"The word does not exist.\n";
        }
        
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Unordered map behavior on clear and reserve
    By golfinguy4 in forum C++ Programming
    Replies: 16
    Last Post: 01-01-2015, 06:32 AM
  2. implementing with map, and unordered map
    By jaesungj in forum C++ Programming
    Replies: 0
    Last Post: 11-08-2013, 09:45 AM
  3. Replies: 5
    Last Post: 06-30-2011, 10:29 PM
  4. Creating Objects On The Heap And Adding Them To A List
    By SomeBeginner in forum C++ Programming
    Replies: 2
    Last Post: 09-25-2002, 04:01 PM
  5. Adding objects to an array
    By Unregistered in forum C++ Programming
    Replies: 3
    Last Post: 11-27-2001, 09:24 AM