Hello.

I've just discovered that I didn't think a cunning plan all the way through.

I've got a grid with a bunch of columns and rows holding CStrings. What I'm doing is trying to filter the grid to only display certain strings. The user selects a location in the grid, and all the rows with the same string in the same column are filtered from the grid.

I've got that working. Mostly.

I've got a map using the CString entry to be filtered out as the key, and the column number as the value. This works fine and dandy, and lets me take back filters if necessary without reloading the entire grid's contents.

The problem is: I can get the same string in two columns, and the code is written such that it won't allow the same key to be filtered twice.
This seemed smart at the time.

Now, I've just realized that there may be cases when the user wants several (probably " ") strings filtered out, but they will be prevented from doing so by the code.

At this point, I'm thinking a multimap would be better, because I think that a multimap would allow several instances of " " to be entered as a key to several columns.

True?

If so, how in blazes does one know if the results of multimapname.find("Whatevah") will give me access to the correct value (ie, column) I want to check?

I haven't adapted this program for multimap yet; I'm just trying to figure out how it would work if I could use the multimap container.

Thanks in advance.

>how in blazes does one know if the results of multimapname.find
>("Whatevah") will give me access to the correct value (ie, column) I want to check?
One doesn't know. The order of duplicates in a multimap is unspecified.

Oh. Well, that's not very good for this application, then... And it seems like my plan really was pretty dumb.

Can anyone suggest a better storage class for this problem?

Otherwise, I'll have to go with a multimap and an iterative search by key and value. I don't think the user will generate thousands of filters, so it shouldn't be too expensive to implement.

How about you keep the same setup except instead of a single column number as the map value, use a vector of column numbers?

Ah, that would be usable, considering the vectors would be for ints, and not require any fooling around with the operator overloads.
Nice.

But.. Um... Would that be a declaration like this?

typedef pair <const CString,vector<int>> cCStr2IntVect;	
	
	//Map for recording single string filters and the columns. Strings are the keys, because they don't repeat.
	// The second entry is the column number the filter was performed in.
	map <CString,vector<int>> Stringfilt;			
	map <CString,vector<int>>:: iterator strIter;

The compiler's unhappy with that, even though it's got the vector header.
error C2146: syntax error : missing ',' before identifier 'cCStr2IntVect'
error C2065: 'cCStr2IntVect' : undeclared identifier
error C2143: syntax error : missing '>' before ';'
error C2208: 'struct std:: pair' : no members defined using this type

And that's just for the typedef pair line. Any idea what I'm messing up?

>Any idea what I'm messing up?
Put a space between the closing angle brackets. The parser is reading that as a bitwise right shift:

typedef pair <const CString,vector<int> > cCStr2IntVect;

Lather, rinse, repeat.

...
That's horrifying. Thanks!

It seems to mostly be compiling. I'm doing the additions thusly:

strIter = Stringfilt.find(filterStr);
	if(strIter!= Stringfilt.end())
	{
		for(vIter=strIter->second.begin();vIter!=strIter->second.end(); vIter++)
		{
			if(*vIter==fCell.col)		//Have already encountered this string and column pairing.
				return;
		}
		strIter->second.push_back(fCell.col);//.insert(fCell.col);		
	}
	else
	{
		strIter->second.push_back(fCell.col);		
	}

Weird... But I think it'll work.

EDIT: Correction. It compiles, but has problems with the dbgheap... I need to think about this some more... ...
Crud. Day's nearly gone. Haven't gotten anything done 'cause of bad design.

Here's what seems to work, but I'm nervous about memory leaks.

In the header, I have the following declarations.

typedef pair <const CString,vector<int> > cCStr2IntVect;	
	
	vector <int>::iterator vIter;
	
	//Map for recording single string filters and the columns. Strings are the keys, because they don't repeat.
	// The second entry is the column number the filter was performed in.
	map <CString,vector<int> > Stringfilt;			
	map <CString,vector<int> >:: iterator strIter;
	
	//Map for recording filter other calls.Strings are the keys, because they don't repeat. 
	//The second entry is the column number the filter was performed in.
	map<CString,vector<int> > Otherfilt;		
	map<CString,vector<int> >::iterator othIter;

Then, I assign new values to the filter map thusly.
I looked through the watch vectors, and they seem to be storing the information correctly. But I also see the vector destructor operating... I can only assume that's just on the local copy of v1, because the information persists in Stringfilt.

CString filterStr = m_pGrid->GetItemText(fCell.row,fCell.col);
	
	strIter = Stringfilt.find(filterStr);
	if(strIter!= Stringfilt.end())
	{
		for(vIter=strIter->second.begin();vIter!=strIter->second.end(); vIter++)
		{
			if(*vIter==fCell.col)		//Have already encountered this value
				return;
		}
		strIter->second.push_back(fCell.col);	
	}
	else
	{
	//First occurance of this filter.

		vector<int> v1( 1,fCell.col);
		Stringfilt.insert(cCStr2IntVect(filterStr,v1));

	}

	for(int i = 0;i<pDoc->vectlen; i++)
	{
		if(!pDoc->packlist[i].hidden)
		{
			if(filterStr==m_pGrid->GetItemText((i+1),fCell.col))
			{
				pDoc->packlist[i].hidden=HIDDEN;
			//	m_pGrid->SetRowHeight((i+1),0); //Hide row.				
			}
			else if(!firstflag &&(i>fCell.row-1)) //Find first instance of packet that won't be filtered AFTER the packet defining the filter
			{
			firstflag=1;
			pDoc->iter=&pDoc->packlist.at(i); //note, when i 13, packet number is 14. 
			//break; //Exit loop.
			}
		}
		
		if(!firstflag && (i==(pDoc->vectlen-1))) //At final packet, and it's hidden
		{
			//firstflag = 1;
			for(int z = fCell.row-2;z>0;z--) 
			{

				if(!pDoc->packlist[z].hidden) //Find packet closest to the filtered one that isn't filtered.
				{
					firstflag =2;
					pDoc->iter=&pDoc->packlist[z];						
					break;
				}
			}//end for(z)
		}
	}//end for (i)

And I'm using this to clean up memory.

void CGUISnoopView::FilterWipe()
{
	for(strIter=Stringfilt.begin(); strIter!=Stringfilt.end();strIter++)
	{
		strIter->second.clear();
	}
	Stringfilt.clear();

	
	for(othIter=Otherfilt.begin(); othIter!=Otherfilt.end();othIter++)
	{
		othIter->second.clear();
	}
	Otherfilt.clear();
}

I'm sure I'm messing up somewhere.

This article has been dead for over six months. Start a new discussion instead.