Checking if Container has Value (c++) - c++

I have a custom class 'team' and one of its attributes is its 'name.' After each 'team' is created, I add it to a vector teamList.
I would like to implement a function that continuously prompts the user for a team name which is not already taken by a team within the teamList. I have the following code:
while (true) {
string newString;
bool flag = true;
getline(cin, newString);
for (int i = 0; i < teamList.size(); i++) {
if (teamList[i].name.compare(newString) == 0) flag = false;
}
if (flag == true) {
return newString;
} else {
cout << "name already taken." << endl;
}
}
However, this code is really ugly; is there a better way to check? Also, a more general question- faced with an issue of ugly code (like this one), what kinds of steps can I take to find a new, cleaner implementation? Thanks.

I would use std::set, which deals with duplicates for you. As an example, you can see that the class is sorted by the string member, and when three are inserted in main, only two stay because two of the insertions have the same string, so they are treated equal.
#include <iostream>
#include <set>
#include <string>
struct SetThing {
SetThing(int value, const std::string &value2) : i(value), s(value2){}
int i;
std::string s;
bool operator<(const SetThing &other) const {
return s < other.s;
}
};
int main() {
std::set<SetThing> s;
s.insert(SetThing(5, "abc"));
s.insert(SetThing(4, "def"));
s.insert(SetThing(6, "abc"));
std::cout << s.size();
}
Now for inserting, you can just reprompt while the second member of the returned pair is false:
do {
//get input
} while (!teamList.insert(somethingBasedOnInput).second);

define an equality operator in team that can compare a team to a string:
bool team::operator==(string s) const
{
return(s==name);
}
Then you can use find:
vector<team>::const_iterator itr = find(teamList.begin(), teamList.end(),
newString);
if(itr!=league.end())
cout << "name already taken" << endl;

Related

How to overload == operator to see if two objects with a string vector are equal?

I am writing a class named StringSet which has vector<string> data and int length as its private members.
bool StringSet::operator == (StringSet d)
{
for (int i = 0; i < length; i++)
{
if (data[i] == d.data[i])
{
return true;
}
}
return false;
}
When I try calling this function like this,
StringSet doc1, doc2;
if (doc1 == doc2)
{
cout << "Both sentences are identical!\n";
}
I get an assertion failure saying vector subscript out of range, I know what that means but I don't know how it implies here. If anyone can point out an obvious mistake I have made that would be great as I am a newbie to c++.
It's simple
bool StringSet::operator == (const StringSet& d) const
{
return data == d.data;
}
std::vector and std::string have already comparison operators, therefore you don't have to implement something special.

How can I pass std::cin as an argument for a function?

I've searched for answers on stackoverflow and am simply not getting it. A well-explained answer would be amazing.
Here's my incomplete code for a password validator. I ask for user input and then run it through a series of boolean functions to decide whether it meets the strong password criteria.
If you find any other errors(which I'm sure there is), please let me know. Thanks!
#include <iostream>
#include <ctype.h>
#include <cstring>
//DECLARING GLOBAL VARIABLES
bool isLong;
bool hasDigits;
bool hasAlphabets;
bool hasSpecial;
//FUNCTION TO CHECK IF PASSWORD IS LONG ENOUGH
bool checklen(std::string x)
{
if (x.length() > 8)
{
isLong = true;
}
else if (x.length() < 8)
{
isLong = false;
}
return isLong;
}
//FUNCTION TO CHECK IF PASSWORD HAS DIGITS
bool checkdigits(std::string x)
{
for (int i = 0; i < x.length(); i++)
{
if (isdigit(x[i]))
{
hasDigits = true;
}
else if (not isdigit(x[i]))
{
hasDigits = false;
}
}
return hasDigits;
}
//FUNCTION TO CHECK IF PASSWORD HAS ALPHABETS
bool checkalphabets(std::string x)
{
for (int i = 0; i < x.length(); i++)
{
if (isalpha(x[i]))
{
hasAlphabets = true;
}
else if (not isalpha(x[i]))
{
hasAlphabets = false;
}
}
return hasAlphabets;
}
//MAIN FUNCTION THAT RUNS THE VALIDATION AND HANDLES LOGIC
int main()
{
std::cout << "enter new password: ";
std::string password{};
std::cin >> password;
checklen(password); //trying pass the stored cin value as argument.
checkdigits(password); //trying to pass the stored cin value as argument.
checkalphabets(password); //trying to pass the stored cin value as argument.
//the functions literally use "password" as a string instead of the stored user input.
if (isLong = true)
{
if (hasDigits = true)
{
if (hasAlphabets = true)
{
std::cout << "Your password is strong";
}
}
}
else
{
std::cout << "Your password is still weak";
}
return 0;
}
#include <iostream>
#include <algorithm>
bool isLong(std::string x)
{
return x.length() > 8;
}
bool hasDigits(std::string x)
{
return std::any_of(x.begin(), x.end(), ::isdigit);
}
bool hasAlpha(std::string x)
{
return std::any_of(x.begin(), x.end(), ::isalpha);
}
bool isStrong(std::string x)
{
return isLong(x) and hasDigits(x) and hasAlpha(x);
}
int main()
{
std::string password;
std::cout << "enter new password: ";
std::cin >> password;
if (isStrong(password))
std::cout << "Your password is strong";
else
std::cout << "Your password is weak";
return 0;
}
I assume by
If you find any other errors(which I'm sure there is), please let me
know. Thanks!
you want to find the most 'efficient' program.
The most important error was that you used one equality sign instead
of two. This meant that you were simply assigning a value to a
variable in the if statements, not checking for equality.
Your checklen function returns an uninitialised boolean if
the length of the password is exactly 8.
Your checkdigits function has a logic error. The
return value depends on the last character checked - not the whole
string. If the last character was a digit, it would return true,
else it would return false, not taking in account the whole
string.
The same logic error as above was also in the checkalphabets
function.
There is no need to include an empty initialiser list for the declaration of a std::string.
The nesting of if loops is not necessary as you can simply use && operators.
Your program does not output "Your password is still weak" in the case where the password has no digits and is not alphabetical. It only outputs the above if the password is not long enough.
Global variable use is unnecessary in the program and is frowned upon when dealing with best programming practices. They are available to all functions, classes - however, if you were to define a variable of the same name, there would be a redeclaration error. (This is just one problem when using global variables.)
The code I posted above is what I would consider "optimal". It uses built-in functions to reduce code complexity and is much more consider.
If you are new to programming (which I will assume), I would recommend you try 'dry running' your code as this will help you identify the logic errors.
The syntax error of the equality signs should be picked up by a good compiler. (Or rather, logic error, as the syntax is 'valid' but 99% of the time is not what is intended.)
Inefficiencies in the program code can be reduced with experience (such as the nested if loops).
How can I pass std::cin as an argument for a function?
std::cin is an std::istream. Thus, the way to pass it to a function is like this:
void function(std::istream& stream) {
// implmentation...
}
Note: I believe you can't pass std::istreams by value. You must pass it by reference.
Then you call it like this:
function(std::cin);
Please note that you have other bugs in your program explained better in the other answer. But that's how you generally pass std::cin to a function.

Table Representation in C++

Basically, say, I have the following data:
(let me note that the columns change with every piece of data I get, i.e. I need to keep things general and cannot restrict my solution to only Tenor, Date, etc.)
Now I want to be able to represent and conveniently access this data in an object/class in C++.
I have been playing around with map a bit:
#include <iostream>
#include <map>
#include <string>
using namespace std;
class my_table {
private:
map<string, map<string, string>> c;
public:
void set(string key1, string key2, string value){ this->c[key1][key2] = value; }
string get(string key1, string key2){
map<string, map<string, string>>::iterator it = this->c.find(key1);
if (it != this->c.end()){
map<string, string>::iterator it2 = this->c[key1].find(key2);
if (it2 != this->c[key1].end()){
return c[key1][key2];
}
return "n/a";
}
return "n/a";
}
};
void main() {
my_table a;
a.set("1", "Tenor", "1D");
cout << a.get("1", "Tenor") << endl; // returns '1D'
cout << a.get("2", "Tenor") << endl; // returns 'n/a'
cout << a.get("1", "Rate") << endl; // returns 'n/a'
}
But I am not overly satisfied with this implemenation. In particular, I would want to be able to do things like:
a.get("Tenor","3M", "Rate") // should return '1.6%'
a.get("Date","01-Jan-2016", "Responsibility") // should return 'MG'
a.get_all("Type","Forward", "Rate") // should return an array {1.3%,2.4%}
a.get_row(4) // should return an array {4M,...,2.0%,MG}
And:
I am wondering whether there are there any standard packages that could help me simplify this implementation overall?
In particular, my get function seems unnecessarily cumbersome.
And generally, is map is even the right way to go in terms of storing data like this?
And what if I wanted to generalise this implemenation to more than just 2 keys? Maybe 3 keys. My solution is quite rigid
enum struct Type {
Spot
Forward
}
struct Row {
string tenor;
Date date;
int convention;
Type type;
double rate;
ResposibilityType responsibility;
};
std::vector<Row> table = {
[...]
}
access you do with std::find_if. Tables in databases might be stored like this internally. If you want multiple primary keys you can create for each key a map that maps from the primary key to an element in table. If you want a combined key, you need tuple like this std::map<std::pair<Key1,Key2>, Row*>
How about the matrix type from boost.ublas? You can create a simple enum type to easily reference columns.
For querying you can probably build something quick via the filter_iterator.
Hope this helps!
Edit: Sorry didn't notice your comment. A quick hack I can think of to support dynamic column size is using a hash map for storing column name to column index mapping in a separate hash map. Good luck!
Limiting yourself to maps could overcomplicate this somewhat. If I understand this correctly, the data structure is completely undefined at compile time. In that case perhaps a simpler way to implement it is as a vector of hash-key-value triples, like this:
#include "stdafx.h"
#include <string>
#include <vector>
#include <iostream>
using namespace std;
class HashKeyValue
{
private:
string hash;
string key;
string value;
public:
HashKeyValue() {}
HashKeyValue(string h, string k, string v)
{
hash = h;
key = k;
value = v;
}
string getHash() { return hash; }
string getKey() { return key; }
string getValue() { return value; }
};
class my_table
{
private:
vector<HashKeyValue> hkv;
public:
my_table() {}
void set(string h, string k, string v)
{
hkv.push_back(HashKeyValue(h, k, v));
}
string getV(string h, string k)
{
for (unsigned int i = 0; i < hkv.size(); i++)
{
if (hkv[i].getHash() == h && hkv[i].getKey() == k)
return hkv[i].getValue();
}
return "n/a";
}
string getByColValue(string col1, string val, string col2)
{
string hash;
int got = 0;
for (unsigned int i = 0; i < hkv.size() && !got; i++)
{
if (hkv[i].getKey() == col1 && hkv[i].getValue() == val)
{
hash = hkv[i].getHash();
got = 1;
}
}
if (got)
{
for (unsigned int i = 0; i < hkv.size(); i++)
{
if (hkv[i].getHash() == hash && hkv[i].getKey() == col2)
return hkv[i].getValue();
}
return "n/a";
}
else return "n/a";
}
};
int main()
{
my_table m;
m.set("1", "Tenor", "1D");
m.set("3", "Tenor", "3M");
m.set("3", "Rate", "1.6%");
cout << "get-1-Tenor(1D): " << m.getV("1", "Tenor") << endl;
cout << "get-1-Alto(n/a): " << m.getV("1", "Alto") << endl;
cout << "get-3-Rate(1.6%): " << m.getV("3", "Rate") << endl;
cout << "getBCV-Tenor-3M-Rate(1.6%): " << m.getByColValue("Tenor", "3M", "Rate") << endl;
return 0;
}
Hopefully getByColValue() makes sense; it first looks up the hash, then looks up the Rate for that hash. The hash is what relates each key-value pair to others on the same row. It shouldn't be too tricky to change getByColValue() to return a vector<string> instead, for the getByColValue("Type","Forward","Rate") case: just make hash a vector<string> instead, define the return type as another vector<string>, and a few other tweaks.
This also makes the implementation of getRow() fairly trivial; just loop over hkv where hash==rowid and bung the key/value pairs (or just the values) into a vector.

Open hashing, add element, and find element using iterator

I have an open hash table using the STL.
typedef std::list<int> LIST;
typedef std::vector<LIST> HASH_TABLE;
I initialized the hash table by filling it with empty lists.
LIST mt_list;
HASH_TABLE hTable;
hTable.assign(7, mt_list);
Now if I want to add an int to my table based on:
hKey = (value*value) % 7;
and I use
hTable[hKey].push_back(value);
It should work right? I can't get it to work.
void addValue(int value){
if(val_find(value)){
std::cout << "WARNING: duplicate input: " << value << std::endl;
}
else{
calc_hash_bucket(value); //set hKey
hTable[hKey].push_back(value); //push value into list
}
}
The code above does not add the element to any of the lists within the vector.
Also, when I want to use an iterator to traverse the vector and the lists within the vector, how do I get one element at a time from a list so I can find a particular value that may or may not already be in the list?
This is what I have for finding a value within the hash table:
bool val_find(int value){
if(mt_hash()){
return false;
}
else{
for(HASH_ITER h_iter = hTable.begin(); h_iter != hTable.end(); ++h_iter){
for(LIST_ITER l_iter = h_iter->begin(); l_iter != h_iter->end(); ++l_iter){
if(*l_iter == value){
return true;
}
}
}
}
return false;
}
I'm stumped. I don't understand why it won't add the value to any of the lists.
I feel I should mention this is all in a header file and part of a class that I created. (I don't know if that matters)
Edit: The warning statement does not print. To answer questions, the mt_hash() function checks to see if the hash table is empty and I have checked it several times to make sure it outputs correctly. I fixed the hTable_1 vs hTable difference, they are the same thing. I just forgot to change it when I put it into the question.
bool mt_hash(void){ //is hash table empty?
for(unsigned int i = 0; i < hTable.size(); ++i){
if(!hTable.at(i).empty()){ //if not empty return false
return false;
}
}
return true; //else return true
}
Thanks,
Zach
As Pradhan points out, there is a quite a bit missing. What is the implementation of mt_hash()? Are hTable_1 and hTable the same object?
Below, I've taken your code above, and placed them in a struct with the implied functionality included. Note three changes: hTable replaces hTable_1 in val_find(); addValue() uses a local variable to store the hash key; and mt_hash() is implemented by keeping a simple element count.
#include <list>
#include <vector>
#include <iostream>
#include <iomanip>
struct open_hash {
typedef std::list<int> LIST;
typedef std::vector<LIST> HASH_TABLE;
typedef LIST::const_iterator LIST_ITER;
typedef HASH_TABLE::const_iterator HASH_ITER;
HASH_TABLE hTable;
int nbins;
int elem_count;
explicit open_hash(int nbins_): nbins(nbins_), elem_count(0) {
init_hash();
}
void init_hash() {
LIST mt_list;
hTable.assign(nbins, mt_list);
}
int hash_bucket(int value) const {
return (value*value)%nbins;
}
bool mt_hash() const {
return elem_count==0;
}
bool val_find(int value) const {
if (mt_hash()) {
return false;
}
for (HASH_ITER h_iter = hTable.begin(); h_iter != hTable.end(); ++h_iter){
for (LIST_ITER l_iter = h_iter->begin(); l_iter != h_iter->end(); ++l_iter){
if (*l_iter == value) {
return true;
}
}
}
return false;
}
void addValue(int value) {
if (val_find(value)) {
std::cout << "WARNING: duplicate input: " << value << std::endl;
}
else {
int hKey=hash_bucket(value);
hTable[hKey].push_back(value); //push value into list
++elem_count;
}
}
};
int main() {
open_hash H(7);
std::vector<int> vals={3,1,9,2,10,4,3};
for (int v: vals) {
H.addValue(v);
}
for (int i=1; i<=10; ++i) {
std::cout << "val_find(" << i << "):\t" << std::boolalpha << H.val_find(i) << "\n";
}
}
This produces expected output:
WARNING: duplicate input: 3
val_find(1): true
val_find(2): true
val_find(3): true
val_find(4): true
val_find(5): false
val_find(6): false
val_find(7): false
val_find(8): false
val_find(9): true
val_find(10): true
I suspect the original problem lies in addValue() and val_find() referring to different hash objects, or a problem in mt_hash() misreporting that the table is empty when in fact it is not.
The answer to the this problem is to create the class object of type HASH_TABLE in the main cpp file and then pass it by reference into the function (getCmd) that calls all of the commands and i/o.
I was calling the "getCmd" function in main() and that function (EVERY time it is called) creates a NEW instance of the HASH_TABLE class, effectively "replacing" the previous object with a new, empty object. (though I suspect it did not actually replace the previous object. I think the previous object was still taking up memory but it was not being used)
I didn't post the code for the problem area because I didn't know where the problem was.
Thanks for all your help!

Where is the operator "<" used in this sample?

I tried STL sample program using "map".
http://ideone.com/LB8xvh
#include <iostream>
#include <map>
#include <cstring>
using namespace std;
class ItemName
{
char name[80];
public:
ItemName(char *s) { strcpy(name, s); }
char *get() { return name; }
};
bool operator<(ItemName a, ItemName b)
{
return strcmp(a.get(), b.get()) < 0;
}
class ItemObj
{
char str[80];
public:
ItemObj(char *s) { strcpy(str, s); }
char *get() { return str; }
};
char itemdata[][80] = {
"potion", "heal HP",
"key", "unlock a door",
"lamp", "light",
};
int main() {
map<ItemName, ItemObj> items;
for(int i=0; i<3; i++) {
items.insert(
pair<ItemName, ItemObj>(
ItemName(itemdata[i*2]),
ItemObj(itemdata[i*2+1]))); // ***** pair *****
}
map<ItemName, ItemObj>::iterator p;
char str[80];
const int kMaxLoop = 5;
int nLoop = 0;
while(nLoop < kMaxLoop) {
cout << "> ";
cin >> str;
p = items.find(str);
if(p != items.end() ) {
cout << p->second.get() << endl;
} else {
cout << "unknown item." << endl;
}
nLoop++;
}
return 0;
}
In this example, I am not quite sure where the operator "<" is used.
If I comment out the definition of the operator "<", I receive lots of errors.
std::map has a parameter to specify how to compare elements in the map (needed because a map always maintains its contents sorted in order by key). By default, that's std::less<T>.
std::less<T>, in turn, will do the comparison using operator<.
You can create a map of items for which operator< isn't defined, but to do it you need to specify the comparison function/functor explicitly.
That said: your ItemData and ItemObj are both really just doing things that std::string can already do. You could reduce most of the code above to something like this:
std::map<std::string, std::string> items{
{ "potion", "heal HP" },
{ "key", "unlock a door" },
{ "lamp", "light" }
};
It is used internally by the map to place and find entries. Otherwise, find would have to compare the key you supply it against literally every single other entry one by one and you couldn't iterate the map in key order.
Basically, maps efficiently store elements in order. To do that, they have to have some way to know what the order is, and they do that by calling operator< (unless you specify otherwise).