Witam Bracia i Siostry w kodzie
Co uważacie na temat klasy jaką wykoncypowałem, aby rozwiązać zagadnienie własnej, niealfabetycznej kolejności sortowania listy obiektów?
customsortorder.h
/* The class determines custom sort order for items displayed in AddEquipmentItem groups. It does so by checking passed InventoryItem field with the first occurence of matching regexp from
* appropriate vector xxxSortOrderVector.
*/
class CustomSortOrder
{
public:
static void sortItems(QList<const InventoryItem*> &itemsToSort, const QString &groupName);
private:
QVector<QString> ballisticSortOrderVector;
QVector<QString> energySortOrderVector;
QVector<QString> missileSortOrderVector;
QVector<QString> supportSortOrderVector;
QVector<QString> ammoSortOrderVector;
QVector<QString> gyroSortOrderVector;
QVector<QString> actuatorsSortOrderVector;
QVector<QString> computersSortOrderVector;
QVector<QString> heatsinksSortOrderVector;
CustomSortOrder();
};
customsortorder.cpp
CustomSortOrder::CustomSortOrder()
{
ballisticSortOrderVector.append("^AC/2(\\D|$)");
ballisticSortOrderVector.append("^AC/5(\\D|$)");
ballisticSortOrderVector.append("^AC/10(\\D|$)");
ballisticSortOrderVector.append("^AC/20(\\D|$)");
ballisticSortOrderVector.append("^Gauss Rifle(.|$)");
//as it turned out additional ^ in regexps was required, otherwise it matched M Laser in ER M Laser
energySortOrderVector.append("^M Laser(.|$)");
energySortOrderVector.append("^ER M Laser(.|$)");
energySortOrderVector.append("^M Pulse(.|$)");
energySortOrderVector.append("^L Laser(.|$)");
energySortOrderVector.append("^ER L Laser(.|$)");
energySortOrderVector.append("^L Pulse(.|$)");
energySortOrderVector.append("^PPC(.|$)");
energySortOrderVector.append("^ER PPC(.|$)");
missileSortOrderVector.append("^SRM2(\\D|$)");
missileSortOrderVector.append("^SRM4(\\D|$)");
missileSortOrderVector.append("^SRM6(\\D|$)");
missileSortOrderVector.append("^LRM5(\\D|$)");
missileSortOrderVector.append("^LRM10(\\D|$)");
missileSortOrderVector.append("^LRM15(\\D|$)");
missileSortOrderVector.append("^LRM20(\\D|$)");
supportSortOrderVector.append("^S Laser(.|$)");
supportSortOrderVector.append("^ER S Laser(.|$)");
supportSortOrderVector.append("^S Pulse(.|$)");
supportSortOrderVector.append("^MG(.|$)");
supportSortOrderVector.append("^Flamer(.|$)");
ammoSortOrderVector.append("^SRM.");
ammoSortOrderVector.append("^LRM.");
ammoSortOrderVector.append("^MG.");
ammoSortOrderVector.append("^AC/2 A.");
ammoSortOrderVector.append("^AC/5 A.");
ammoSortOrderVector.append("^AC/10 A.");
ammoSortOrderVector.append("^AC/20 A.");
ammoSortOrderVector.append("^Gauss.");
gyroSortOrderVector.append("^- ");
gyroSortOrderVector.append(" Hit Defense");
gyroSortOrderVector.append(" Melee");
actuatorsSortOrderVector.append("Melee Dmg");
actuatorsSortOrderVector.append("Stb");
actuatorsSortOrderVector.append("DFA Dmg");
actuatorsSortOrderVector.append("DFA Self");
computersSortOrderVector.append("Ballistic");
computersSortOrderVector.append("Energy");
computersSortOrderVector.append("Missile");
heatsinksSortOrderVector.append("Sink$");
heatsinksSortOrderVector.append("\\(D\\)$");
heatsinksSortOrderVector.append("^Exchanger");
heatsinksSortOrderVector.append("Bank");
}
void CustomSortOrder::sortItems(QList<const InventoryItem*> &itemsToSort, const QString &groupName)
{
static CustomSortOrder cso;
std::function<const QString&(const InventoryItem *item)> fieldToSortOn;
fieldToSortOn = [](const InventoryItem *item)->const QString&
{
return item->name;
};
QVector<QString> *sortOrderToUse = nullptr;
if (groupName == Categories::ballistic)
{
sortOrderToUse = &cso.ballisticSortOrderVector;
}
else if (groupName == Categories::energy)
{
sortOrderToUse = &cso.energySortOrderVector;
}
else if (groupName == Categories::missile)
{
sortOrderToUse = &cso.missileSortOrderVector;
}
else if (groupName == Categories::support)
{
sortOrderToUse = &cso.supportSortOrderVector;
}
else if (groupName == Categories::ammo)
{
sortOrderToUse = &cso.ammoSortOrderVector;
}
else if (groupName == Categories::heatsinks)
{
sortOrderToUse = &cso.heatsinksSortOrderVector;
}
else//non-name based sorting
{
if (groupName == Categories::gyros)
{
sortOrderToUse = &cso.gyroSortOrderVector;
}
else if (groupName == Categories::actuators)
{
sortOrderToUse = &cso.actuatorsSortOrderVector;
}
else if (groupName == Categories::computers)
{
sortOrderToUse = &cso.computersSortOrderVector;
}
else//no match to any mentioned groupName, so keep name field as sort base
{
goto skipFieldChange;//jump down
}
fieldToSortOn = [](const InventoryItem *item)->const QString&
{
return item->bonusValueA;
};
}
skipFieldChange:
std::function<bool(const InventoryItem *item1, const InventoryItem *item2)> sortLambda;
sortLambda = [sortOrderToUse, fieldToSortOn](const InventoryItem *item1, const InventoryItem *item2)->bool
{
QString field1 = fieldToSortOn(item1);
QString field2 = fieldToSortOn(item2);
if (sortOrderToUse != nullptr && sortOrderToUse->size() > 0)
{
QRegularExpression regExp;
regExp.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
int index1 = -1, index2 = -1;
for (int cnt = 0; cnt < sortOrderToUse->size(); cnt++)
{
regExp.setPattern(sortOrderToUse->value(cnt));
if (index1 < 0 && regExp.match(field1).hasMatch())
{
index1 = cnt;
}
if (index2 < 0 && regExp.match(field2).hasMatch())
{
index2 = cnt;
}
if (index1 >= 0 && index2 >= 0)
{
break;
}
}
//both fields are found in sort order vector
if (index1 >= 0 && index2 >= 0)
{
if (index1 != index2)
{
return index1 < index2;
}
//in the case of same InventoryItem fields the one with shorter name should be considered lesser
if (field1.size() != field2.size())
{
return fieldToSortOn(item1).size() < fieldToSortOn(item2).size();
}
}
//if only one of the passed InventoryItems matched regexp stored in sort order vector the one which has match should be considered smaller
if (index1 >=0 && index2 < 0)
{
return true;
}
if (index1 < 0 && index2 >= 0)
{
return false;
}
}
//preform ordinary alphabetical sort for equipment names not included in sortOrderVectors
//return field1 < field2;
return item1->name < item2->name;
};
std::sort(itemsToSort.begin(), itemsToSort.end(), sortLambda);
}