Using the TList class to reorder multiple fields - c++

int __fastcall ListSortFunc1(void *Item1, void *Item2)
{
MyStruct *item1 = (MyStruct*)Item1;
MyStruct *item2 = (MyStruct*)Item2;
return (item1->string1 < item2->string1) ? (item1->string1 > item2->string1) :
StrToInt64(item1->number1) - StrToInt64(item2->number1);
}
Reading the online documentation, it is not very clear how to use the Sort method.
My need is to reorder two or more fields. Currently, I have to reorder a file where the first field is numeric, the second is the date, the third a string, the fourth still a string.
I did some tests with Excel and with the code that it reports, but I get completely different results.
Can anyone kindly provide me with directions?

TList::Sort() is passed a callback function that is called during sorting to compare pairs of values from the list. The callback is expected to conform to the specification of the TListSortCompare type. Per its documentation:
Item1 and Item2 are 2 elements from the list. When these are passed to the TListSortCompare function, the Sort method is asking which order they should be in. The comparison returns a value determined by the relative values of Item1 and Item2, as shown in this table:
Value
Description
>0 (positive)
Item1 is greater than Item2
0
Item1 is equal to Item2
<0 (negative)
Item1 is less than Item2
Your function does not satisfy that requirement.
When item1->string1 is less than item2->string1, you are returning 0 when you should be returning a negative value.
Otherwise, you return the result of subtracting item2->number1 from item1->number1. But you are comparing the number1 fields when item1->string1 is greater than or equal to item2->string1. You should be comparing the number1 fields only when the string1 fields are equal. Also, you are risking overflows by using subtraction if the number1 fields have large values.
Try something more like this instead:
int __fastcall ListSortFunc1(void *Item1, void *Item2)
{
MyStruct *item1 = static_cast<MyStruct*>(Item1);
MyStruct *item2 = static_cast<MyStruct*>(Item2);
if (item1->string1 == item2->string1)
{
// simply subtracting the values could lead to integer overflows
// for large values, so just compare the values as-is...
// Also: why are these not stored as __int64 to begin with?
__int64 int1 = StrToInt64(item1->number1);
__int64 int2 = StrToInt64(item2->number1);
if (int1 < int2) return -1;
if (int1 > int2) return 1;
return 0;
}
else
{
return (item1->string1 < item2->string1) ? -1 : 1;
// or:
return CompareStr(item1->string1, item2->string1); // case sensitive
// or:
return CompareText(item1->string1, item2->string1); // case insensitive
}
}

Related

How to custom sort a VCL TListBox?

I'm trying to figure out how to supply my own custom sort method to items and strings in a TListBox.
My list box stores a custom object in its Object property, and I need to use that in the custom sort.
I'm basing the below code on this post (Delphi): Is it possible to sort a TListBox using a custom sort comparator?
My custom sort function looks like this
int __fastcall SortListByValue (TStringList* sl, int item1, int item2)
{
IniKey* k1 = (IniKey*) sl->Objects[item1];
IniKey* k2 = (IniKey*) sl->Objects[item2];
return k1->mValue < k2->mValue;
}
The key values are strings. Currently they can be "-", "Yes", "No" and "Pass".
And the code where it is called is like this:
void __fastcall TMainForm::sortByValueAExecute(TObject *Sender)
{
Log(lInfo) << "Sorting list based on Values";
TStringList* sl = new TStringList();
sl->Assign(imagesLB->Items);
sl->CustomSort(SortListByValue);
imagesLB->Items->Assign(sl);
}
The above code does "something" to the list, but its not sorted.
The resulting list starts with "-" items, and all "Yes" items are consecutive. "No" and "Pass" and "-" items are then scrambled.
Any clues?
Your sort function is expected to return a value that is < 0, 0, or > 0, depending on the desired order of the two input parameters. But you are not doing that correctly. You are returning either 0 or 1, but never < 0, because you are returning the (implicitly converted) result of a boolean expression, which can only be false or true.
You need to change this line:
return k1->mValue < k2->mValue;
To this instead:
if (k1->mValue < k2->mValue) return -1;
else if (k1->mValue > k2->mValue) return 1;
else return 0;
Alternatively, use the RTL's AnsiCompareStr() or CompareStr() function instead:
return AnsiCompareStr(k1->mValue, k2->mValue);
return CompareStr(k1->mValue, k2->mValue);

Sitrecore MinValue

I need to sort very large number of item in Sitecore.
So I used negative number, something like this:
item.sortOrder = int.MinValue + someId
minValue = -2147483647
but sitecore sort correctly only for value greater then -2143053648 so there is a difference of 4430001
so now my code is
item.sortOrder = int.MinValue + 4430001 + someId
and it sorts correctly
does anyone ever experienced something like this, am I doing something wrong?
I'm not sure what exactly you are trying to achieve but it would be better to define a public constant for Sitecore SortOrder Minimum value somewhere accessible.
public const int SortOrderMinimumValue = -2143053648;
And then reference like this
item.Fields["__Sortorder"].Value = SortOrderMinimumValue + someId;
That way the minimum value can be accessed any other code and can be altered at one location should you want to change the minimum value for your sorting.
To sort Items by sort order you then will need to do the following
public class ItemComparer : IComparer
{
public int CompareSortOrder(Item item1, Item item2)
{
int sortOrder1;
bool parsed1 = int.TryParse(item1["__Sortorder"], out sortOrder1);
int sortOrder2;
bool parsed2 = int.TryParse(item2["__Sortorder"], out sortOrder2);
if (!parsed1 || !parsed2)
throw new Exception("Sort order value is incorrect type");
if (sortOrder1 < sortOrder2)
return -1;
if (sortOrder1 > sortOrder2)
return 1;
else
return 0;
}
}
And then reference the code when sorting;
var itemComparer = new ItemComparer();
items.Sort(itemComparer.CompareSortOrder);

Find minimum value different than zero given some conditions

I've started learning C++ Sets and Iterators and I can't figure if I'm doing this correctly since I'm relatively new to programming.
I've created a Set of a struct with a custom comparator that puts the items in a decreasing order. Before receiving the input I don't know how many items my Set will contain. It can contain any number of items from 0 to 1000.
Here are the Setdefinitions:
typedef struct Pop {
int value_one; int node_value;
} Pop;
struct comparator {
bool operator() (const Pop& lhs, const Pop& rhs) const {
if (rhs.value_one == lhs.value_one) {
return lhs.node_value < rhs.node_value;
} else { return rhs.value_one < lhs.value_one;}
}
};
set<Pop, comparator> pop;
set<Pop>::iterator it;
And this is the algorithm. It should find a minimum value and print that value. If it does not find (the function do_some_work(...) returns 0), it should print "Zero work found!\n":
int minimum = (INT_MAX) / 2; int result;
int main(int argc, char** argv) {
//....
//After reading input and adding values to the SET gets to this part
Pop next;
Pop current;
for (it = pop.begin(); it != pop.end() && minimum != 1; it++) {
current = *it;
temp_it = it;
temp_it++;
if (temp_it != pop.end()) {
next = *temp_it;
// This function returns a integer value that can be any number from 0 to 5000.
// Besides this, it checks if the value found is less that the minimum (declared as global) and different of 0 and if so
// updates the minimum value. Even if the set as 1000 items and at the first iteration the value
// found is 1, minimum is updated with 1 and we should break out of the for loop.
result = do_some_work(current.node_value);
if (result > 0 && next.value_one < current.value_one) {
break;
}
} else {
result = do_some_work(current.node_value);
}
}
if (minimum != (INT_MAX) / 2) {
printf("%d\n", minimum);
} else {
printf("Zero work found!\n");
}
return 0;
}
Here are some possible outcomes.
If the Set is empty it should print Zero work found!
If the Set as one item and do_some_work(current.node_value) returns a value bigger than 0 it should printf("%d\n", minimum); or Zero work found! otherwise.
Imagine I have this Set (first position value_one and second position node_value:
4 2
3 6
3 7
3 8
3 10
2 34
If in the first iteration do_some_work(current.node_value) returns a value bigger than 0, since all other items value_one are smaller, it should break the loop, print the minimum and exit the program.
If in the first iteration do_some_work(current.node_value) returns 0, I advance in the Set and since there are 4 items with value_one as 3 I must analyze this 4 items because any of these can return a possible valid minimum value. If any of these updates the minimum value to 1, it should break the loop, print the minimum and exit the program.
In this case, the last item of the Set is only analysed if all other items return 0 or minimum value is set to 1.
For me this is both an algorithmic problem and a programming problem.
With this code, am I analysing all the possibilities and if minimum is 1, breaking the loop since if 1 is returned there's no need to check any other items?

Recursive Function Error

Im trying to create a recursive function that contains a vector of numbers and has a key, which is the number we are looking for in the vector.
Each time the key is found the function should display a count for how many times the key appears in the vector.
For some reason my recursive function is only returning the number 1 (disregard the 10 I was just testing something)
Here's my code:
int recursive_count(const vector<int>& vec, int key, size_t start){
if (start == vec.size())
return true;
return (vec[start] == key? 23 : key)
&& recursive_count(vec, key, (start+1));
}
int main() {
vector <int> coco;
for (int i = 0; i<10; i++) {
coco.push_back(i);
}
cout << coco.size() << endl;
int j = 6;
cout << recursive_count(coco, j, 0) << endl;
}
Not sure what you are trying to do, but as is - your function will return false (0) if and only if the input key is 0 and it is in the vector. Otherwise it will return 1.
This is because you are basically doing boolean AND operation. The operands are true for all values that are not 0, and the only way to get a 0 - is if it is in the vector - and the key is 0.
So, unless you get a false (0) along the way, the answer to the boolean formula is true, which provides the 1.
EDIT:
If you are trying to do count how many times the key is in vec - do the same thing you did in iterative approach:
Start from 0 (make stop condition return 0; instead of return true;)
Increase by 1 whenever the key is found instead of using operator&&, use the operator+.
(I did not give a direct full answer because it seems like HW, try to follow these hints, and ask if you have more questions).
To me it seems that a recursive function for that is nonsense, but anyway...
Think about the recursion concepts.
What is the break condition? That the current character being checked is not in the string anymore. You got that right.
But the recursion case is wrong. You return some kind of bool (what's with the 23 by the way?
The one recursion round needs to return 1 if the current element equals key, and 0 otherwise.
Then we only need to add up the recursion results, and we're there!
Here's the code
int recursive_count(const vector<int>& vec, int key, size_t start) {
if (start >= vec.size()) {
return 0;
} else {
return
((vec[start] == key) ? 1 : 0) +
recursive_count(vec, key, start+1);
}
}
Since this is even tail-recursion, good compilers will remove the recursion for you by the way, and turn it into its iterative counterpart...
Your recursive_count function always evaluates to a bool
You are either explicitly returning true
if (start == vec.size())
return true;
or returning a boolean compare
return (vec[start] == key? 23 : key) // this term gets evaluated
&& // the term above and below get 'anded', which returns true or false.
recursive_count(vec, key, (start+1)) // this term gets evaluated
It then gets cast to your return type ( int ), meaning you will only ever get 0 or 1 returned.
As per integral promotion rules on cppreference.com
The type bool can be converted to int with the value false becoming
​0​ and true becoming 1.
With,
if (start == vec.size())
return true;
your function with return type int returns 1

Algorithm for index range of values in stl vector

I have a table of data as shown below. Note here is that keyID can be duplicates. I have collected below data in vector structure, which is sorted.
struct myData {
int keyID;
int value;
}
vector<myData> vecReadFromFile;
Now user enters a particular keyID, and I have to check if that value exits in vector, if exits I have to return that value. If not I have to check between which values it fall for example if user enters 120030, value falls between 120028 and 120039 here I should get index of these values i.e., lowerIndex and upperIndex in this example '2' and '3' (as vector index starts at 0)
If user enters less keyID i.e., 120001 then return no value. Similarly user enters keyID greater than last key value then return an different error code.
Basically I want to find index range of given key value effectively. I have added code which is present seems not working for above example I mentioned what is bug?
I can change logic to use STL provided algortihms. Please suggest.
How we can achive this algorithm effectively in C++? Request with sample code as function. Note here I will call function many times in my project so it has to effective.
keyID Value
120002 10
120025 20
120028 25
120039 30
120042 -
120048 40
120052 50
120112 60
120117 70
120123 70
120126 80
120130 90
I have some code here
//==========================================================================
// FindBounds
bool FindBounds(const KEY& cTarget, UINT& uLower, UINT& uUpper)
{
uLower = -1;
uUpper = -1;
// start with full range of data.
uLower = 0;
uUpper = m_uCount-1; // Here I have m_uCount as vector.size()
// narrow the bounds as much as possible.
while (uUpper - uLower > 1 && cTarget != m_pKeys[uLower])
{
// split the range in half and discard the half that the key does not belong to.
UINT uBound = uUpper - (uUpper-uLower)/2;
// keep the lower range.
if (KeyInRange(uLower, uBound, cTarget))
{
uUpper = uBound;
}
// keep the upper range.
else
{
uLower = uBound;
}
}
}
bool KeyInRange(UINT uLower, UINT uUpper, const KEY& cTarget)
{
// check if target is within range.
if (m_pKeys[uLower] <= cTarget)
{
if (m_pKeys[uUpper] > cTarget || (m_pKeys[uLower] == cTarget && m_pKeys[uLower] == m_pKeys[uUpper]))
{
return true;
}
}
// target is not within range.
return false;
}
Thanks for your time and help
There is the std::equal_range algorithm.
std::lower_bound() from STL, <algorithm> header:
http://en.cppreference.com/w/cpp/algorithm/lower_bound
1)I think if you are going to lookup some values by their keys better to choose STL container multiset, which allows key duplicates.
2) see methods lower_bound() and upper_bound() they might be applicable to that you are trying to do