I have now fixed the incorrect sorting in V6 sorting. Yuki, your data is now sorted correctly by V6 as well.
For sorting, I have divided the Sort value into an odd slot (999999, 999997, 999995, etc.) and an even slot (999998, 999996, 999994, etc.).
When processing the entries, RefEntries always get an odd sort value, while the directly parent entry always gets an even sort value. Of course there can be duplications, because with iterative referencing a RefEntry can be a parent entry at the same time, but two directly related entries never get the same sort value.
I tried to optimize the procedure even more by storing the sort values directly in the list, as far as it was possible. So that when transferring the sort values from the map to the list later, not all values have to be transferred.
V6 is similar to your latest V4. I also have two list passes, as you did in V4. But although in V4 you do not need the subsequent copying of the sort values from the map to the list and V4 seems less complicated than V6, V6 performs better than all other versions up to about 5500 entries. For me it is not quite clear why this is so.
Yes, that is absolutely correct.Yuki wrote: Relying on the dirtied map for sort logic has the downside that whenever elements change, you have to properly invalidate the map. Affecting only the changed element might be coincidentally safe in some cases, but you'd really have to walk relations to be sure, which is relatively costly with the existing structure. This is good if your list is fixed after creation, but otherwise may cost more in the long run.
However, due to the use case (arranging GUI elements in a window), I would limit myself to re-sorting the list when (subsequently) adding or removing a gadget.
I'm not sure yet how to implement this, because it makes absolutely no sense to re-sort the entire list internally for *every* AddGadget() or RemoveGadget() function. Even if the sorting is lightning fast by now, it would still be completely wasted resources for no reason.
I'm still thinking about whether I should provide the user with a separate command for this (e.g. InitGadgetlist() )... or whether I should let the module's resize procedure do the list sorting and detect whether the gadget list is invalid or not yet initialized. Then the sorting would be done completely transparently in the background, which would benefit the user-friendliness of the module.
For this I would need a fast method to hash all entries in the list and then compare this hash value with a stored hash value generated during the last sort.
Here now the actual V6 procedure and a few timing measurements.
Code: Select all
Procedure.i SortList_V6()
	Protected.i *RefEntry.MyStruct, iSort = 999998
	
	With StructList()
		ForEach StructList()
			; We process only the entries with a RefEntry
			If \RefEntry <> ""
				*RefEntry = FindMapElement(StructMap(), \RefEntry)
				; Invalid reference entry detected
				If *RefEntry = 0
					ProcedureReturn -1
				EndIf
				If *RefEntry\Sort = 0
					; The Entry with a not yet processed RefEntry gets the current sort value
					; Only the even slots are used for this (999998, 999996, 999994, etc.)
					\Sort = iSort
					StructMap(\Entry)\Sort = iSort
					iSort - 2
				Else
 					; If the RefEntry has already been edited, then the parent element gets
 					; the next higher sort value in the odd slots (999999, 999997, 999995, etc.) 
					\Sort = *RefEntry\Sort + 1
					StructMap(\Entry)\Sort = \Sort
				EndIf
			Else
				; Entries without RefEntry are marked with sort = 1
				\Sort = 1
			EndIf
		Next
	EndWith
	
	ForEach StructList()
		; We update the list, but only the entries with sort = 0 to save some execution time.
		; Only these entries contain uninitialized data.
		; All other list entries have already been updated in the loop above.
		If StructList()\Sort = 0
			StructList()\Sort = StructMap(StructList()\Entry)\Sort
		EndIf
	Next		
	
	SortStructuredList(StructList(), #PB_Sort_Ascending, OffsetOf(MyStruct\Sort), TypeOf(MyStruct\Sort))
	ProcedureReturn 0
	
EndProcedure
Code: Select all
Listsize: 24
V3 Algorithm: 14 microseconds.
V4 Algorithm: 6 microseconds.
V5 Algorithm: 18 microseconds.
V5 extended: 22 microseconds.
V6 Algorithm: 3 microseconds.
Listsize: 96
V3 Algorithm: 49 microseconds.
V4 Algorithm: 21 microseconds.
V5 Algorithm: 50 microseconds.
V5 extended: 57 microseconds.
V6 Algorithm: 17 microseconds.
Listsize: 240
V3 Algorithm: 102 microseconds.
V4 Algorithm: 41 microseconds.
V5 Algorithm: 71 microseconds.
V5 extended: 83 microseconds.
V6 Algorithm: 34 microseconds.
Listsize: 2400
V3 Algorithm: 1680 microseconds.
V4 Algorithm: 663 microseconds.
V5 Algorithm: 718 microseconds.
V5 extended: 738 microseconds.
V6 Algorithm: 533 microseconds.
Listsize: 5520
V3 Algorithm: 6409 microseconds.
V4 Algorithm: 2195 microseconds.
V5 Algorithm: 1818 microseconds.
V5 extended: 1853 microseconds.
V6 Algorithm: 1870 microseconds.


 


 
 


