470,818 Members | 1,587 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 470,818 developers. It's quick & easy.

std::list Duplicates with Different Data

How do I work with a std::list that might have multiple objects
having the same "key", but which have other data that is different?
Here's code that compiles, but doesn't do quite what I expect:
(Please note that there's some specialized I/o code here, but the
logic flow should be clear...)

struct GenCheck // Gender Check data
{
char genCode;
int useCount;
string firstName;

bool operator==(const GenCheck &rhs) const
{
return firstName == rhs.firstName;
}

bool operator<(const GenCheck &rhs) const
{
return firstName < rhs.firstName;
}

bool operator==(const string &rhs) const
{
return firstName == rhs;
}

bool operator<(const string &rhs) const
{
return firstName < rhs;
}

} gWork;
typedef list<GenCheckNAMES;
NAMES genData;
list<GenCheck>::iterator gIter;

void nameGenderFile() // maintain NAMECHK.DAT file
{
int ii, jj = 0, kk = 0, mCt = 0, fCt = 0, uCt = 0;
char gCode;
Str24 sName, fName, lName, priorName = "";

strcpy(f3, "myfile.hst"), fv3.openFile("", f3, "", "rt");
while(getFinData(&fv3)) // *** this is my own I/o routine
{
strcpy(sName, FinData.EN), splitNames(sName, fName, lName);
if(strcmp(sName, priorName) == 0) continue; // same name
else strcpy(priorName, sName);
gCode = FinData.Sx, strcpy(sName, t_f.upper(TTB(fName))), kk++;
gIter = find(genData.begin(), genData.end(), sName);
if(gIter != genData.end()) // found a match
{
gWork = (*gIter);
if(gCode != gWork.genCode) // gender mismatch
{ // gender mismatch - make entry for other gender
gIter = find(gIter, genData.end(), sName);
if(gIter != genData.end()) // found another match
{ // update count for different gender
gWork = (*gIter), gWork.useCount++;
continue;
}
else
{ // different gender's object doesn't exist
// *** The following code block doesn't execute: if there isn't another
// matching name, this code should create a new std::lst object with the
// same name but different gender. That is, if the first "CHRIS" is a
// female, the code below (logic #2) creates a new std:list object (and
// it does), but if a 2nd "CHRIS" is found that's a male, this code
// should create a new std::list object.
// It doesn't... 8<{{
//
gWork.genCode = gCode, gWork.useCount = 1;
gWork.firstName = sName;
switch(gCode)
{
case 'F': fCt++; break;
case 'M': mCt++; break;
}
genData.push_back(gWork);
sprintf(emsg, "Males: %d Females: %d", mCt, fCt);
fastWrite(2, DSLINE, HINORM, emsg);
}
} // if
else
{ // name/gender match - adjust count
gWork.useCount++;
*gIter = gWork;
}
}
else // this name isn't on the database
{
// *** logic #2
gWork.genCode = gCode, gWork.useCount = 1;
gWork.firstName = sName;
switch(gCode)
{
case 'F': fCt++; break;
case 'M': mCt++; break;
}
genData.push_back(gWork);
sprintf(emsg, "Males: %d Females: %d", mCt, fCt);
fastWrite(2, DSLINE, HINORM, emsg);
}
} // while
fv3.closeFile();
return;
} // nameGenderFile

What have I done wrong here? Please advise. TIA
Jun 27 '08 #1
3 1433
In article <MP************************@news.cox.net>, mr*****@cox.net
says...
How do I work with a std::list that might have multiple objects
having the same "key", but which have other data that is different?
Here's code that compiles, but doesn't do quite what I expect:
[ ... ]
What have I done wrong here? Please advise. TIA
Based on what you've posted, it's a _little_ difficult to be certain,
but my immediate guess would be "almost everything." You apparently have
keys and data that's associated with those keys -- in which case,
std::map or std::multimap is the data structure you probably want to
use. Between those, std::map requires that each key be unique, where
std::multimap allows more than one item with a specific key. Your
statement above appears to indicate the latter. You haven't, however,
made entirely clear _what_ data you're associating with each key.
Looking at your code, it looks like you're just counting the number of
times each key occurs.

My advice would be to give us a post that describes what you're really
trying to accomplish, and we can probably help you write code that
accomplishes what you want. I'd start with the format of the file you're
reading, and the output you need to produce from it.

As it stands right now, I doubt that most of the advice you've gotten is
very likely to help you produce a really good result. Most of it is
based on fixing the details of your code, but I don't think those
details will mean much until you've fixed some basic principles.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jun 27 '08 #2
In article <MP************************@news.sunsite.dk>,
How do I work with a std::list that might have multiple objects
having the same "key", but which have other data that is different?
Here's code that compiles, but doesn't do quite what I expect:

[ ... ]
What have I done wrong here? Please advise. TIA

Based on what you've posted, it's a _little_ difficult to be certain,
but my immediate guess would be "almost everything." You apparently have
keys and data that's associated with those keys -- in which case,
std::map or std::multimap is the data structure you probably want to
use. Between those, std::map requires that each key be unique, where
std::multimap allows more than one item with a specific key. Your
statement above appears to indicate the latter. You haven't, however,
made entirely clear _what_ data you're associating with each key.
Looking at your code, it looks like you're just counting the number of
times each key occurs.

My advice would be to give us a post that describes what you're really
trying to accomplish, and we can probably help you write code that
accomplishes what you want. I'd start with the format of the file you're
reading, and the output you need to produce from it.

As it stands right now, I doubt that most of the advice you've gotten is
very likely to help you produce a really good result. Most of it is
based on fixing the details of your code, but I don't think those
details will mean much until you've fixed some basic principles.
Yes, this is true. Also, there have been a lot of comments on my
coding _style_, which haven't been useful: I have been programming
computers for 48+ years, and new paradigms are not always easy to adopt.
8<{{
Okay, here's what I am trying to do:
1. I have a large file with names (in the form "last, first") and
gender codes ('M'/'F') from which I want to parse the "first" name
string and build a std::list (or some other container type) of all
unique (first) names and genders.
2. I intend to use this information in a data entry application that
checks the validity of a inputted first_name against this data
collection. If there's a conflict (e.g. "SUE",'M', or "MARVIN",'F'), I
want the application to pause and let the user decide if that's correct.
3. There are cases ("PAT", "CHRIS", etc.) where the name is valid,
regardless of gender. Therefore, the std::list should contain multiple
objects that have the same "search key" value (e.g. "CHRIS") but have
different gender codes - 2 different objects with identical "find"
values. I am struggling with (1) building the std::list and (2)
searching it for all possible variations of name & gender.
BTW, I appreciate the helpful response, Jerry...
Jun 27 '08 #3
In article <MP************************@news.cox.net>, mr*****@cox.net
says...

[ ... ]
Okay, here's what I am trying to do:
1. I have a large file with names (in the form "last, first") and
gender codes ('M'/'F') from which I want to parse the "first" name
string and build a std::list (or some other container type) of all
unique (first) names and genders.
2. I intend to use this information in a data entry application that
checks the validity of a inputted first_name against this data
collection. If there's a conflict (e.g. "SUE",'M', or "MARVIN",'F'), I
want the application to pause and let the user decide if that's correct.
3. There are cases ("PAT", "CHRIS", etc.) where the name is valid,
regardless of gender. Therefore, the std::list should contain multiple
objects that have the same "search key" value (e.g. "CHRIS") but have
different gender codes - 2 different objects with identical "find"
values. I am struggling with (1) building the std::list and (2)
searching it for all possible variations of name & gender.
BTW, I appreciate the helpful response, Jerry...
First of all, I would _not_ use a linked list. Second, I'd use a single
entry for each first name, storing the number of males and number of
females with that first name. I believe that should simplify your code
quite a bit. Personally, I'd write the code something like this:

// Warning: all code in the post is UNTESTED!
// data is it's read from the file:
struct person {
std::string fname;
std::string lname;
char gender;
};

// read the data from the file:
std::istream &operator>>(std::istream &is, person &p) {
// assumes file is of form: last_name ',' first_name ',' gender '\n'
is.getline(p.lname, ',');
is.getline(p.fname, ',');
is >p.gender;
if (is.peek() != '\n')
is.setstate(std::ios::failbit);
return is;
}

enum gender { MALE, FEMALE };

// holds the data we care about:
struct name_use {
std::string first_name;
long f_use;
long m_use;

name_use(std::string name, gender g) :
first_name(name), f_use(0), m_use(0)
{
if (g==MALE)
++m_use;
else
++f_use;
}

bool operator<(name_use &other) {
return first_name < other.first_name;
}
};

std::set<name_usenames;

std::ifstream input("myfile.hst");

person temp;

while (input>>temp) {
gender g = temp.gender == 'M' ? MALE : FEMALE;

name_use nu(temp.fname, gender);

std::set<name_use>::iterator it = names.find(nu);

if (it != names.end()) {
// name found -- increment appropriate count
if (gender == MALE)
++it->m_use;
else
++it->f_use;
}
else { // name not present yet
names.insert(nu);
}

To put this to use, you'd set a threshold, and check whether the value
was below that threshold:

const double threshold = 0.05;

person p;
get_data(input, p);
std::set<name_use>::iterator n = names.find(person.fname);

if ((n == names.end())
// maybe a typo?
warn("Please verify name");
else {
double percent_male = double(n->m_use)/(n->f_use+n->m_use);
double percent_female = 1.0 - percent_male;

if (p.gender == 'M' && (percent_male < threshold))
warn("Please verify gender");
else if (p.gender == 'F' && (percent_female < threshold))
warn("Please verify gender");
}

There are, of course, a number of alternatives, such as using an
std::map, with the first name as the key and the usages as the
associated data. This might be a tad cleaner in places, but I doubt the
difference would be particularly major.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jun 27 '08 #4

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

14 posts views Thread by Dave | last post: by
2 posts views Thread by Morten Aune Lyrstad | last post: by
8 posts views Thread by emanshu | last post: by
25 posts views Thread by Markus Svilans | last post: by
7 posts views Thread by alex221 | last post: by
7 posts views Thread by TBass | last post: by
11 posts views Thread by Juha Nieminen | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.