I've implemented a wxListCtrl and would like to sort the list alphabetically. Although this sounds similar as the question here, it is different with one major difference: I'm using SetItemData() and GetItemData() to store the index of a vector.
The code supplied here works nicely, but requires GetItemData(). Even though the comparison function does not refer to any of the item data, if I omit it, the sorting is not complete.
static int wxCALLBACK MyCompareFunction(long item1, long item2, long sortData) {
wxSortedListCtrl *ctrl = (wxSortedListCtrl*) sortData;
wxString a, b;
a = ctrl->GetItemText(item1, ctrl->GetSortedColumn());
b = ctrl->GetItemText(item2, ctrl->GetSortedColumn());
if( ctrl->IsSortedAscending() )
return a.CmpNoCase(b);
return b.CmpNoCase(a);
}
bool wxSortedListCtrl::SortItems(void) {
long item = -1;
for ( ;; ) {
item = GetNextItem(item);
if ( item == -1 )
break;
SetItemData(item, item);
//this is needed even though MyCompareFunction doesn't use it AT ALL.
//however it overwrites the data that I use myself...
}
return wxListCtrl::SortItems(MyCompareFunction, (long)this);
}
How would I use this sort function while maintaining the item data I've set myself with SetItemData()?
If you want to rely on the control to do the sorting (as opposed to resorting the items internally and just reinserting them into it in the correct order), you must be able to access the sort key (i.e. text in your case) via the item data. So, instead of just associating your own data with each item, associate some struct containing both the item text and your custom data with it.
Alternatively, use wxLC_VIRTUAL and just override OnGetItemXXX() to return the items in the correct order. This may sometimes be simpler than dealing with sorting the items manually and is definitely much more efficient for any non-trivial number of items.
Related
I have a global list of items (each with a few properties) in a module of my program. It's immutable and statically defined in the code, so no worries there.
For instance let's say I have vegetables, which are just an alias defining them to an immutable tuple with name (string), code (ubyte) and price (ushort).
I'd like to be able to access those either by name or by code ; so I thought since the list of vegetables is known at compile-time, I could probably construct associative arrays with references to these vegetables (so string=>vegetable and ubyte=>vegetable)
Here's the kind of thing I am trying to achieve :
static struct instructions
{
// list of Veggies
immutable instr[] list = [
Veggie("Potato" , 0xD0, 2),
Veggie("Carrot" , 0xFE, 5),
];
// genByCode and genByName being pure functions that get CTFE'd
// and return the desired associative array
immutable instr[ubyte] byCode = genByCode(list);
immutable instr[string] byName = genByName(list);
// overloaded function returns the right Veggie
instr get(string name) const
{ return byName[name]; }
instr get(ubyte code) const
{ return byCode[code]; }
}
With those generator functions (separated for clarity) of the form
pure instr[ubyte] genByCode(immutable Veggie[] list)
{
instr[ubyte] res;
foreach (i ; list)
res[i.code] = i;
return res;
}
I spent quite some time messing around but I couldn't it to work. Of course it would be trivial to construct at runtime, but clearly it should be possible to do it at compile time.
At first I thought it was an issue of mutability, so I tried marking everything (vegetables and vegetable lists) as immutable (as they should be anyway), but then I ran into issues which I think regard immutable tuples, and feel too lost to keep going.
Could I get help from someone with a clearer overview of the mechanisms at play here ? Thanks !
The data is already there, no need to construct a compile-time associative array.
Just iterate over it statically:
static auto get(int code)(){
static foreach(veggie; list)
static if(veggie.code == code)
return veggie;
}
...
void main(){
writeln(instructions.get!0xD0);
}
It may be slower than access through a hash map, but that's the life of CTFE.
To make sure it evaluates at compile time, you can use this:
template get(int code){
static foreach(veggie; list)
static if(veggie.code == code)
alias get = veggie;
}
I have a vector of (pointers to) objects - people. I have a function that adds income to a person. The problem I'm having is to both find a person and accessing that addInc. I still sometimes get confused with pointers/references and more importantly I'm new to OOP. The relevant function is:
bool Population::Income(const string &id, unsigned int amount) {
Person *Candidate = new Person(id);
//find company using lower_bound
iterPeople = lower_bound(m_People.begin(), m_People.end(), Candidate, cmpId);
if ( iterPeople != m_People.end() && (*iterPeople)->m_id == id ) {
*(iterPeople)->addInc(amount);
//request for member 'addInv' in...maybe you meant to use '->'?
delete Candidate;
return true;
}
delete Candidate;
return false;
The rest of the code is HERE. I have two questions:
How do I solve the addInc issue?
About the lower_bound search - that method should be fine with NewPersonor CancelPerson but Income is gonna get called A LOT. Is that method sufficiently quick? Any way to make it more efficient?
BONUS - with addInc also comes MedianNetworth which returns median of all successfully added Incomes. The efficient way to use this is to create two heaps (min and max). My initial plan was to make_heap in the Population class:
make_heap(m_Audits.begin(), m_Audits.end(), cmpInt);
however I cannot make a heap inside the class because of unexpected '(' token - the very same syntax works in main() or inside any function. What am I doing wrong? Obviously I don't want to create heaps inside functions since I would have to create a new heap whenever I wanted to add an entry.
I've been reading about keeping functions simple and specific to only one purpose. And that even a function that does a simple calculation and print out the result is already too much.
I've been working on an item shop system for a small game. The shop has a vector of all items available in the game. Each Item keeps track of its own count (is that bad?), and do not show up in the inventory output if its count is zero.
When a player (rider) wants to buy an item, the shop should check if the player has enough credit and if such item is in stock before the item gets removed from the shop (and then added to the player's inventory).
I have combined all of that into one function, thinking that this avoid repetition of traversing through the vector of Items.
/* ItemShop.cpp
* non-binary boolean:
* returns 0 if item is not in stock
* returns 1 if rider has insufficient creds to buy the item
* returns 2 if purchase is successful */
int ItemShop::buyItem(const string& itemName, const int cred, Item& newItem) {
// go through shop inventory and search for item with given name
for (int i = 0; i < items.size(); i++) {
if (items[i].getName() == itemName) {
if (items[i].getCount() > 0) { // item is in stock
if (items[i].getValue() <= cred) { // rider has enough creds to buy the item
newItem = items[i]; // pass a copy of the item by ref
newItem.setCount(1); // take one of that item
items[i].removeOne(); // remove one from the shop
return 2; // purchase is successful
}
return 1; // rider cannot afford to buy the item
}
}
}
return 0; // item is not in stock
}
In doing this approach, I end up with a larger multi-purpose function but I didn't have to go through the Item vector multiple times. I think if I were to break the function into separate ones, they would be:
check if item is in stock
check if player can afford
transaction
Each of those functions would have to go through and find the item in the vector (unless maybe I pass a reference of it.. from the function?).
All in all, does less code repetition make my approach justifiable? If not, how should I break it down?
Two recommendations:
Store your items in a std::map<string,Item> where the string is
the item name. This will remove the search loop.
Use an enum as return value instead of an int.
You could also implement simple functions for the different checks, but that's a matter of taste I would say.
You can break that up into the following operations:
find the appropriate item by name (that's what the loop mainly does) and return a reference to the found item
check if there are enough items in stock. item itself already carries that information as it looks, it doesn't need to be executed inside the loop
check if the player can afford it. You already have the cred value apparently, it doesn't need to be executed inside the loop
if the latter two conditions are fulfilled do the transaction, again it doesn't need to be executed inside the loop
Your function doesn't do too many things - you are purchasing an item, which includes those three necessary steps (btw.: aren't you missing the payment?).
However (aside from other things that could be improved), you should make sure that the steps don't get intermingled. In particular avoid nested structures whenever possible.
You could e.g.rewrite your body (without changing the interface) like this:
int ItemShop::buyItem(const string& itemName, const int cred, Item& newItem) {
//find item
auto it = std::find_if(items.begin(), items.end(), [&](const Item& item) {return item.getName() == itemName; });
//Check if Item can be purchased
if (it == items.end() || it->getCount == 0) {
return 0; //item is not in stock
}
if (it->getValue() > cred) {
return 1; //rider can't afford item
}
//buy item
newItem = *it; // pass a copy of the item by ref <- Avoid that if possible
newItem.setCount(1); // take one of that item
it->removeOne(); // remove one from the shop
return 2; // purchase is successful
}
I do think an item keeping its own count is a poor idea. An "inventory" (or something on that order) keeps track of the items in stock and the number of each. An item should be just that: an item.
I think the suggestion to use a [unordered_]map is a good one. It pre-implements what is probably the single most complex part of your current function (though none of it is particularly complex).
Do note that some of this can get much trickier when/if multiple threads get involved. If multiple threads of execution are involved, your current pattern of "if we can do this, then do it" breaks down, because it introduces race conditions. You need to assure that removing the item from inventory and paying for the item happen as a single, atomic, transaction. As long as you're sure it'll only have a single thread of execution involved though, your current method is safe.
Good morning, I'm stuck using a map in the correct way.
Situation
A database table with unique ID and two other codes
ID (long) | Type (long) | Name (string)
to fill the map correctly I've defined it in this way:
map<long, MyObject>
where key is my ID and the object holds all the stuff. The map works correctly, I load all rows and I navigate easily inside of it.
Troubles
Troubles come when I need to sort the rows using a criteria which is not the key but:
Type
Name
Looking around the Internet I found that I should:
Define the operator< for MyObject or...
Define another type of comparator for my map.
I did the step 1., but with no success (it is never called). I'm trying to do the point 2. but with even less success.
I'll paste some code to help:
class CSitoWebRigaVariante
{
public:
bool m_bSriDelete;
bool m_bSriVisibile;
long m_lSriId;
long m_lSriIdTipol;
long m_lSriCodGes;
CString m_strSriCodMat;
public:
CSitoWebRigaVariante(void);
CSitoWebRigaVariante(const CSitoWebRigaVariante& cRiga);
~CSitoWebRigaVariante(void);
bool operator<(const CSitoWebRigaVariante& cRiga);
void operator=(const CSitoWebRigaVariante& cRiga);
void Azzera(void);
static void CaricaDaMDB(CDB* pDB, long lIdVM, map<long, CSitoWebRigaVariante>& cRighe);
};
typedef map<long, CSitoWebRigaVariante> CSWRighe;
///> Static method to fill a map.
void CSitoWebRigaVariante::CaricaDaMDB(CADODatabase* pDB, long lIdVM, map<long, CSitoWebRigaVariante>& cRighe)
{
BOOL bValRit;
CRecordset* pRS;
CSitoWebRigaVariante riga;
CString strInt;
pRS = new CADORecordset(pDB);
strInt.Format(_T("SELECT * FROM SITOWEB_RIVARMAT WHERE sri_idvarmat = %ld;"), lIdVM);
cRighe.clear();
if (pRS->Open(strInt, CADORecordset::openQuery) == TRUE && pRS->GetRecordCount() > 0)
{
while (pRS->IsEOF() == FALSE)
{
bValRit = pRS->GetFieldValue(_T("sri_id"), riga.m_lSriId);
bValRit &= pRS->GetFieldValue(_T("sri_idtipol"), riga.m_lSriIdTipol);
bValRit &= pRS->GetFieldValue(_T("sri_codges"), riga.m_lSriCodGes);
bValRit &= pRS->GetFieldValue(_T("sri_codmat"), riga.m_strSriCodMat);
bValRit &= pRS->GetFieldValue(_T("sri_delete"), riga.m_bSriDelete);
bValRit &= pRS->GetFieldValue(_T("sri_visibile"), riga.m_bSriVisibile);
cRighe.insert(pair<long, CSitoWebRigaVariante>(riga.m_lSriCodGes, riga));
pRS->MoveNext();
}
}
pRS->Close();
delete pRS;
}
I'm using Visual Studio 2010, MFC.
Any help is appreciated.
std::map is not a multi-index associative container. Its find method (and other things) uses the key as a search criteria. There's no possibility to specify another search criteria. It's why it's a "single-index lookup table".
You can use Boost.MultiIndex. It was designed for your case and supports multiple indexes (as the name suggests), both unique and not-unique.
Or you can use multiple map instances with different keys. If keys are not unique you need std::multimap.
I would recommend you to use map for model (for storing data). When you need to display information, you can just output it in the order you need it to be shown. Sorting must be done not at level of storing items, but at level of displaying them.
Although, in each situation you will need to do reordering only once.
Also, if any help is appreciated, I would strongly recommend you to do a
typedef long MyId;
and to use VS 2015.
The map class provides a Compare parameter of the constructor. You could not complete your target by setting Compare as map has only support key compare function.
The first idea of mine is construct a class support your tables schema.
class Example
{
public:
<your code>
void sortByID();
void sortByType();
void sortByName();
private:
long ID_;
long Type_;
string Name_;
};
But it sounds terrible. As once your table change, you should hard copy.So why you just get result using database order by?
I am trying to parse header packet of SIP protocol (Similar to HTTP) which is a text based protocol.
The fields in the header do not have an order.
For ex: if there are 3 fields, f1, f2, and f3 they can come in any order any number of times say f3, f2 , f1, f1.
This is increasing the complexity of my parser since I don't know which will come first.
What should I do to overcome this complexity?
Ultimately, you simply need to decouple your processing from the order of receipt. To do that, have a loop that repeats while fields are encountered, and inside the loop determine which field type it is, then dispatch to the processing for that field type. If you can process the fields immediately great, but if you need to save the potentially multiple values given for a field type you might - for example - put them into a vector or even a shared multimap keyed on the field name or id.
Pseudo-code:
Field x;
while (x = get_next_field(input))
{
switch (x.type())
{
case Type1: field1_values.push_back(x.value()); break;
case Type2: field2 = x.value(); break; // just keep the last value seen...
default: throw std::runtime_error("unsupported field type");
}
}
// use the field1_values / field2 etc. variables....
Tony already gave the main idea, I'll get more specific.
The basic idea in parsing is that it is generally separated into several phases. In your case you need to separate the lexing part (extracting the tokens) from the semantic part (acting on them).
You can proceed in different fashions, since I prefer a structured approach, let us suppose that we have a simple struct reprensenting the header:
struct SipHeader {
int field1;
std::string field2;
std::vector<int> field3;
};
Now, we create a function that take a field name, its value, and fill the corresponding field of the SipHeader structure appropriately.
void parseField(std::string const& name, std::string const& value, SipHeader& sh) {
if (name == "Field1") {
sh.field1 = std::stoi(value);
return;
}
if (name == "Field2") {
sh.field2 = value;
return;
}
if (name == "Field3") {
// ...
return;
}
throw std::runtime_error("Unknown field");
}
And then you iterate over the lines of the header and for each line separate the name and the value and call this functions.
There are obviously refinements:
instead of a if-chain you can use a map of functors or you can fully tokenize the source and store the fields in a std::map<std::string, std::string>
you can use a state-machine technic to immediately act on it without copying
but the essential advice is the same:
To manage complexity you need to separate the task in orthogonal subtasks.