Remove specific items from a listbox in MFC - c++

CString dance[] = {L"Atb", L"Tiesto", L"Madonna", L"Paul van Dyk", L"Armin van Burren", L"Jennifer Lopez"};
for(int i = 0; i < m_ItemsListBox.GetCount(); ++i)
{
CString item;
int length = m_ItemsListBox.GetTextLen(i);
m_ItemsListBox.GetText(i, item.GetBuffer(length));
for(int j = 0; j < sizeof(dance)/sizeof(*dance); ++j)
{
if(item != dance[j])
{
m_ItemsListBox.DeleteString(i);
}
}
}
I'm trying to remove from a listbox(m_ItemsListbox) all elements that are not part from the CString array. But how I coded it doesnt work, because if the first element its different it will delete it without searching the entire array.
Doesn't seemed like a hard task but I really have no idee how to do it. I think one way should be to use a CList instead of the array because it has a find() method, but I don't like it because I have to manually add all the elements, do you guys have another idee? Or the CList solution is the only one ?
Sorry, I'm a MFC begginer. Thanks for your time.

Hmmm I wouldn't be comfortable deleting things from the list box while iterating through the items in the listbox seems to be asking for problems down the line.
Honestly you could do something like this, I've just whipped together - construct a list of all the item indexes you want to remove and remove them at the end.
CList<int, int> ListIndexItemsToRemove;
for(int i = 0; i < m_ItemsListBox.GetCount(); ++i)
{
CString item;
int length = m_ItemsListBox.GetTextLen(i);
m_ItemsListBox.GetText(i, item.GetBuffer(length));
bool isMatchFound = false;
for(int j = 0; j < sizeof(dance)/sizeof(*dance); ++j)
{
if(item == dance[j])
{
isMatchFound = true;
}
}
if (!isMatchFound)
ListIndexItemsToRemove.AddHead(i);
}
for(int i = 0; i < ListIndexItemsToRemove.GetCount(); ++i)
m_ItemsListBox.DeleteString(ListIndexItemsToRemove.GetAt(ListIndexItemsToRemove.FindIndex(i));
but - it may be better to clear the whole list and refill it everytime something changes, as Martin says (if it doesn't affect anything.

For dynamic lists I tend to store data in its own variable and clear/re-populate the list when that data changes. Especially as the list gets bigger re-adding the strings tends to be much faster than doing searches through the list and/or original source.

Related

For loop using pointers to traverse array not working properly

For my homework problem I must use pointers to traverse arrays. When I try to store 3 "name" values into member variables of an array of an Object called RentalAgency, I find that it stores the value, but never increments. Therefore the last value given is stored in the first index and the next two are empty.
RentalAgency *agencies_ptr = agencies;
for(int i = 0; i < 3;i++,++agencies_ptr){
infile.get((agencies->name),MAX_SIZE,space);
}
Where agencies is an array of Objects
If the input is Hertz, Alamo, and Budget, it should output Hertz, Alamo, and Budget.
The actual output is just Budget.
Just write
for(int i = 0; i < 3; i++){
infile.get( agencies_ptr[i].name, MAX_SIZE, space );
}
You are desreferencing agencies, not agencies_ptr (and the parenthesis are not needed):
RentalAgency *agencies_ptr = agencies;
for(int i = 0; i < 3; ++i, ++agencies_ptr)
infile.get(agencies_ptr->name, MAX_SIZE, space);
But a more idiomatic way of traversing a "range" is this (it stands for iterator):
RentalAgency *agencies_it = agencies;
RentalAgency *agencies_end = agencies_it + 3;
for(; agencies_it != agencies_end; ++agencies_it)
infile.get(agencies_it->name, MAX_SIZE, space);
It's cleaner, express intent better and is more familiar to see among experienced programmers.

How to efficiently copy contents between two list controls

I want to copy rows from one List Control to another List Control. I am only able to copy them by sub item. I think this is not very efficient. There must be a method to copy the content by rows. The following is my code that copies content one sub item at a time.
CString CurItem, tem, copystr;
int j = 0;
m_combo_list.GetLBText(m_combo_list.GetCurSel(), CurItem);
for (int i = 0; i < m_list.GetItemCount(); i++) {
tem = m_list.GetItemText(i, 0);
if (CurItem == tem) {
m_report_list.InsertItem(j, _T(""));
for (int k = 0; k < 14; k++) { // 14 items per row.
copystr = m_list.GetItemText(i, k);// get one item per time from one list control.
m_report_list.SetItemText(j, k, copystr); // this is another list control. Copy the item to this list control.
}
j++;
}
}
Could anyone give a method to replace the for loop by copy a row from m_list to m_report_list directly? I think such a way must save a lot of time.

Need to clear Duplicates in a combobox in c++

Basically Title. I have a class with multiple duplicates and I need to get rid of them in my combobox but I have no idea how. Here is my code :
for (int i = 0; i < maxInventaire; i++) {
if (item[i] != NULL) {
cmb_item->Items->Add(gcnew String(item[i]->getNom().c_str()));
}
}
for (int i = 0; i < maxEmployes; i++) {
if (employe[i] != NULL) {
cmb_employe->Items->Add(gcnew String(employe[i]->getNom().c_str()));
}
}
I have more than 20 duplicates the first one. It's a list of items I am using (ex: desktop, laptop, etc) i have stored every one of them in a class with a different id, but their name remains the same, as in desktop.
There must be a way to remove duplicates in those. I have searched everywhere with no luck, I guess you guys here could help me with that.
Thank you!
The easiest way is probably to copy the names into a std::set, and then copy them out of the set into the combo box.
std::set<std::string> names;
for (int i = 0; i < maxInventaire; i++) {
if (item[i] != NULL) {
names.insert(item[i]->getNom())
}
}
for (const auto& name: names) {
cmb_item->Items->Add(gcnew String(name.c_str()));
}
You can also use std::unordered_set, but really the performance difference only becomes significant when you have vastly too many entries for a combo-box, and having the entries in alphabetical order is probably easier than some random order (which is what unordered_set will give).

C++ resize array to smaller size keep same name delete old place in array

I have an array of space object (my thing) that I need to reduce but keep the same name in order to handle some collisions. I set my array up like:
ufo** ufoAr = new ufo*[numberOfUfos];
for (int i=0; i<numberOfUfos; i++) {
ufoAr[i] = new ufo(randomIntBetween(1630, 70), randomIntBetween(860, 45));
}
and when i detect a collision I want to resize my array with two less and delete the two specific elems of array. like here:
//look through all the ufoAr[]
for (int i=0; i<numberOfUfos; i++) {
//look through ufoAr[] again to see other objects
for(int j=0; j<10; j++) {
//if the same
if (i==j){ continue; }
else {
//find a collision
if(ufoAr[i]->collision(ufoAr[j]->sp)) {
//Array::Resize(ufoAr, numberOfUfos-2);
//numberOfUfos = numberOfUfos - 2;
// ------ TRY TO RESIZE ARRAY TO -2 BUT SAME NAME WITHOUT iTH AND jTH ELEM
ufoAlive[i] = false;
ufoAlive[j] = false;
}
}
}
}
I would greatly appreciate any help on resizing the array, thanks in advanced. I am really struggling and need another opinion. thanks
Jack
To do this, you will need to FIRST create a new array, e.g.
ufo** ufoArTmp = new ufo*[numberOfUfos-2];
then copy the contents [you want to keep] of ufoAr into ufoArTmp. Once that is done, you do delete [] ufoAr, and finally ufoAr = ufoArTmp; to update the original pointer. do NOT delete ufoArTmp at this point, as it's the same value as is now in ufoAr, and you want to keep that, right.
Obviously pay special attention to numberOfUfos being less than 2 when you start... ;)
Edit, in reading through the other code:
Don't do this:
if (i==j){ continue; }
else {
much better:
if (i!=j) {
The simplest way to do this is to use std::vector and let that handle the resizing for you.
cplusplus.com reference
cppreference page

Trying to fill a 2d array of structures in C++

As above, I'm trying to create and then fill an array of structures with some starting data to then write to/read from.
I'm still writing the cache simulator as per my previous question:
Any way to get rid of the null character at the end of an istream get?
Here's how I'm making the array:
struct cacheline
{
string data;
string tag;
bool valid;
bool dirty;
};
cacheline **AllocateDynamicArray( int nRows, int nCols)
{
cacheline **dynamicArray;
dynamicArray = new cacheline*[nRows];
for( int i = 0 ; i < nRows ; i++ )
dynamicArray[i] = new cacheline [nCols];
return dynamicArray;
}
I'm calling this from main:
cacheline **cache = AllocateDynamicArray(nooflines,noofways);
It seems to create the array ok, but when I try to fill it I get memory errors, here's how I'm trying to do it:
int fillcache(cacheline **cache, int cachesize, int cachelinelength, int ways)
{
for (int j = 0; j < ways; j++)
{
for (int i = 0; i < cachesize/(cachelinelength*4); i++)
{
cache[i][ways].data = "EMPTY";
cache[i][ways].tag = "";
cache[i][ways].valid = 0;
cache[i][ways].dirty = 0;
}
}
return(1);
}
Calling it with:
fillcache(cache, cachesize, cachelinelength, noofways);
Now, this is the first time I've really tried to use dynamic arrays, so it's entirely possible I'm doing that completely wrong, let alone when trying to make it 2d, any ideas would be greatly appreciated :)
Also, is there an easier way to do write to/read from the array? At the moment (I think) I'm having to pass lots of variables to and from functions, including the array (or a pointer to the array?) each time which doesn't seem efficient?
Something else I'm unsure of, when I pass the array (pointer?) and edit the array, when I go back out of the function, will the array still be edited?
Thanks
Edit:
Just noticed a monumentally stupid error, it should ofcourse be:
cache[i][j].data = "EMPTY";
You should find your happiness. You just need the time to check it out (:
The way to happiness