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).
Related
I have two String Lists and I already have a function that compares two lists to find out which elements of list 2 do not exist in list 1. This block of code works, but maybe it is not the best way to achieve it, there are any other way to get the same result without performing so many iterations with nested loops?
QStringList list1 = {"12420", "23445", "8990", "09890", "32184", "31111"};
QStringList list2 = {"8991", "09890", "32184", "34213"};
QStringList list3;
for (int i = 0; i < list2.size(); ++i) {
bool exists = false;
for (int j = 0; j < list1.size(); ++j) {
if(list2[i] == list1[j]){
exists = true;
break;
}
}
if(!exists) list3.append(list2[i]);
}
qDebug() << list3;
output: ("8991", "34213")
Perhaps this small example does not seem like a problem since the lists are very small. But there might be a case where both lists contain a lot of data.
I need to compare these two lists because within my app, every time a button is clicked, it fetches an existing dataset, then runs a function that generates a new data (including existing ones, such as a data refresh), so I need to get only those that are new and didn't exist before. It might sound like strange behavior, but this is how the app works and I'm just trying to implement a new feature, so I can't change this behavior.
If you switch to QSet<QString>, your code snippet boils down to:
auto diff = set2 - set1;
If the input and output data structures must be QStringLists, you can still do the intermediate computation with QSets and still come out ahead:
auto diff = (QSet::fromList(list2) - QSet::fromList(list1)).toList();
I am trying to go through a txt file with facebook data from 2009 and represent people as vertices on a graph, and friendships as edges. The code to make the graph works perfectly. I used it to calculate the average number of friends that people in this data set had. But when trying to find the average of the average of their friends things get weird. When I try to get the number of friends of a certain friend, the size of that table drastically increases (one time it went from 10 to 988) it keeps doing this until I get a bad_alloc error and im not sure why. How can I access an element without it changing the graph?
while (FacebookInfo >> V1 >> V2 >> garbage) {
unordered_map<int, int>::const_iterator got = graph[V1].find(V2);
if (got == graph[V1].end()) {
graph[V1].insert(make_pair(V2, (int)graph[V1].size()));
graph[V2].insert(make_pair(V1, (int)graph[V2].size()));
}
}
//This is the loop that breaks it
for (int i = 1; i < 63732; i++) {
int averageFriendsOfFriendsForV = 0;
for (int j = 0; j < graph[i].size(); j++) {
int friendOfFriend = graph[graph[i][j]].size(); //this is the line specifically the graph[i][j]
averageFriendsOfFriendsForV += friendOfFriend;
}
averageFriendsOfFriendsForV /= graph[i].size();
totalAvg += averageFriendsOfFriendsForV;
}
Edit: Figured it out, still not sure why it would add data but
for(auto& j : graph[i]){
int friendOfFriend = graph[j.first].size();
etc...
}
fixes it
This always trips me up, if you take a look at the index operator for std::unordered_map, you'll find that it will:
... perform an insertion if such key does not already exist.
So in that loop on the line you suspect:
int friendOfFriend = graph[graph[i][j]].size();
you're probably creating new entries every time which eventually becomes impossible. If you post a bit more code it may be easier to diagnose (since I'm not sure what type graph is in the first place).
Instead of using the operator[], it might be good to do something like:
auto friend = graph.find(i);
if (friend == graph.end()) return;
auto other_friend = graph.find(friend->second);
if (other_friend == graph.end()) return;
or something along those lines where you explicitly check for the existence of the friend.
In this program, the user must type in an 3 letter departing airport code (userFlight) and I will give them back the possible destinations. To check that what they typed in is one of the valid airport codes (departureAirport) I want to compare userFlight and make sure it is one of the possible departureAirports which I have stored in a vector called flights[]. This code obviously isn't working, but is there a similar way to accomplish this?
if
(for (j = 0, j < flights.size, j++)
{
(userFlight != flights[j].departAirport)
})
{return errorCode};
else
{//doSomething()};
If it has a operator< inside which does compare like your condition, how about
if(std::find(flights.begin(), flights.end(), userFlight) != flights.end())
{
/* found */
}
else
{
/* not found */
}
Else, if you don't like that, just check if the loop runs through all indices:
size_t i;
for (i = 0, i < flights.size, i++)
{
if(userFlight == flights[i].departAirport)
break;
}
if(i < flights.size)
{
/* found */
}
else
{
/* not found */
}
But no, a syntax like you want doesn't exist.
The code structure you were aiming for is:
for (j = 0; j < flights.size(); j++)
if (userFlight == flights[j].departAirport)
break;
if ( j == flights.size() ) // we got to the end
return errorCode;
doSomething(j);
However, this is a C-like code style. Not that there is anything wrong with that, but C++ allows for algorithms to be expressed more abstractly (and therefore, easier to read and maintain). IMHO it would be better to use one of the other suggestions such as std::set or std::find_if.
It sounds like you actually want to have a std::set of departing airports.
std::set<std::string> departing_airports = {"DTW", "MKE", "MSP", };
assert(departing_airports.count("DTW") == 1);
Yet another option is std::any_of. Assuming flights contains objects of type Flight:
if (std::any_of(std::begin(flights), std::end(flights),
[&](const Flight& f) { return userFlight == f.departAirport; }))
return errorCode;
doSomething();
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
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.