Jump to content

Help slim down this code involving formlist searches


Recommended Posts

When I call a function F() --fairly isolated incidents, not barrages of calls--it runs searches through a set of formlists looking for a match. The code I have currently is not exactly pretty, but it works perfectly fine. It looks like this:

if !foundalready

	Index = csbmagmarkersNordR.GetSize()
	While (Index > 0 && !foundalready)
		Index -= 1
 		ObjectReference MapMarkerInFormlist = csbmagmarkersNordR.GetAt(Index) As ObjectReference
		ObjectReference RadQuestMapMarker = mapmarkerAlias[QuestIndex].getreference() As ObjectReference
																						
		If (RadQuestMapMarker as objectreference) == (MapMarkerInFormlist as objectreference) 									
			If !foundalready
				FoundLocationIndex = Index
			endif
			FoundLocationType = 2
			foundalready = true
		Endif
	EndWhile
Endif

And then there are perhaps 10 more of these--each a search through a different formlist looking for a match.

The !foundalready -- as you know -- helps skip unnecessary searches through the other formlists once the objectreference is successfully found.

Will using the Find function (instead of what I'm doing here) speed up the searches ? 

Are there other ways to streamline this ?

Link to comment
Share on other sites

Using JContainer's JFormMap, you can build a data structure in which you can avoid searching through lists, arrays or formLists.  I believe it is using trees internally, which will give you logarithmic access times, instead of linear.  The advantage depends on the size of your lists.

Using the native search will definitely be faster than looping in papyrus.  More importantly, it's less code and easier to maintain.

Performance is overrated, if the code works, you should only care about performance when you see a performance problem.

Otherwise, here's one take:

if !foundalready
	ObjectReference RadQuestMapMarker = mapmarkerAlias[QuestIndex].getreference() As ObjectReference
	int i = csbmagmarkersNordR.find( RadQuestMapMarker)
	If i >= 0
		FoundLocationIndex = i
		FoundLocationType = 2
		foundalready = true
	EndIf
Endif

To fast exit a loop, sometimes you can use the "natural" loop control variable instead of making the loop condition more complex:

	While Index > 0
		Index -= 1
		WhatEver()
		If IAmDone()
			index = -1
		Endif
	EndWhile

But really, you should care about making your code correct, readable and readily understandable a LOT MORE than "efficient".

If you have a dozen of these formlist checks to perform, you should wrap the check in a function, and call that function multiple times, instead of duplicating the code.  It adds the overhead of a function call, but we don't care about performance, only correct and readable:

function checkList( int locationType, FormList toCheck, ObjectReference RadQuestMapMarker)
	if !foundalready
		int i = toCheck.find( RadQuestMapMarker)
		If i >= 0
			FoundLocationIndex = i
			FoundLocationType = locationType
			foundalready = true
		EndIf
	Endif
endfunction

...

ObjectReference RadQuestMapMarker = mapmarkerAlias[QuestIndex].getreference() As ObjectReference
checkList( 2, csbmagmarkersNordR, RadQuestMapMarker)
checkList( 3, csbmagmarkersImperialR, RadQuestMapMarker)
checkList( 20, csbmagmarkersVampireR, RadQuestMapMarker)

 

Edited by xkkmEl
Link to comment
Share on other sites

 

ScriptName whatEver extends quest ;anything I just used this

FormList[] Property myList Auto
{10 form lists filled with the creation kit}

int FoundLocationType
int FoundLocationIndex

Bool Function Search(ObjectReference MapMarker)
   Bool isFound = False
   Int i = 0
   Int j = 0
   While !isFound && 0 < myList.Length
      j = myList[i].find(MapMarker)
      If j != -1
         isFound = true
      EndIf
     i += 1 
   EndWhile
   FoundLocationType = i - 1
   FoundLocationIndex = j
   Return isFound
EndFunction

not exactly sure what you want from the locations int, so I did my best.. I do not expect it to be 100% 

you may spin it backward, good luck,  BTW THAT ALL TEN FORMLIST which you and @xkkmEl only hinted at 

Disclaimer the code is untested and just to give @csbx some ideas, Yeah, I like how Find kept neat and tidy and make easy to read tho, and avoid me refactoring, bargain and profit 😊😊😊

Edit saw a mistake in my code))))

 

Edited by PeterMartyr
Link to comment
Share on other sites

I know you like backwards so I change it for you

Bool Function Search(ObjectReference MapMarker)
   Bool isFound = False
   Int i = myList.Length
   Int j = 0
   While !isFound && i > 0
      i -= 1
      j = myList[i].Find(MapMarker)
      If j != -1
         isFound = true
      EndIf
   EndWhile
   FoundLocationType = i
   FoundLocationIndex = j
   Return isFound
EndFunction

PREDICTION:  first time you use a For loop and spin it backwards, my money on you getting an out of bound exception and CTD 😁😁😁if the auto fill does not auto create it for you.. not everything has forgiving as Papyrus 

for (var i = Things.length - 1; i >= 0; i--) {
   Things[i]
}

remember that it is a gift

it may help explain the - 1 on my loop spinning forward, you need to be aware of were that is required OK, as you can seen it is required there and it spinning backwards too, that why I said out of bound exception and CTD 😉😉😉😉 

 

Link to comment
Share on other sites

@csbx whenever I write something that is a known fact, I get attacked by opinionated people with no knowledge of how it actual works, but it was late for  me yesterday and I was tired, but I will tell you today

Arrays

Arrays are fast, they are formula 1 racing cars, but only support data type they declare for,  if one delete  some data in the middle you have empty element, and the length is the same

Now data types have memory allocation and a array whether empty or filled uses the same memory regarding RAM

It also has a fixed sized, and cannot increased it size,  doesn't mean you cannot increase it size though, when it gets filled

  1. declare a bigger temp Array
  2. Copy the Array over to the temp Array
  3. overwrite the original pointer with the new Array
  4. delete the temp Array to release the memory
  5. we have bigger Array with empty elements, using the same pointer or what you call a variable or property 

OFF TOPIC variables or properties contain no data they just pointers 

if you require something from the middle of the Array it works the way you think  data[15 ] =  straight to the index,

Lists

List comes in varieties untold.. and they are objects, but we keep it simple, they use nodes and you traverses the list with the nodes using an iterator, node link the list together 

Spoiler

Singlelinkedlist.png

  1. list that singly linked (1 node) only go one direction forwards
  2. list that are doubly linked (2 nodes) go forwards and backwards

IMPORTANT and my opinion   near as I can ascertain Skyrim lists  are singly linked and cannot be use in a loop backwards, I base this on Skyrim Array Find() and rFind()  List only have Find, there no rFind for list Hee-Hee

https://ck.uesp.net/wiki/FormList_Script

As stated lists use iterators to traverses the nodes, but will go back to that.. just keep it in mind

Spoiler

maxresdefault.jpg

List have no fixe sized, and only used the memory required for data type according to length

if you delete data in middle let's just say it magically heals it's self  and releases the data type memory usage, Hee-Hee and the the length is shorter

head[0A]node[1B]node[2C]node[3D] we will delete [2C]

head[0A]node[1B]node[2D]

LIST CANNOT HAVE EMPTY DATA PRESAY

Now for the iterator, It does exactly what its name implies, and is the only way to traverse a list 

To traverse List iterator use nodes, and nodes link it together and it always start at the beginning, always.. savvy 

Example GetAT(15)

head[o]node[1]node[2]node[3]node[4]node[5node][6]node[7]node[8]node[9]node[10]node[11]node[12]node[13]node[14]node[15]tail

OGM I am at 15 now to get it

But the reality is more like

head[data]node[data]node[data]node[data]node[data]node[data]node[data]node[data]node[data]node[data]node[data]node[data]node[data]node[data]node[data]node[data]

where array use indexes 

[15]

got it, thank you very much

See why arrays are fast?

try to access list only thought their Functions.. in you need to search one use Find, if you need to privately  store data for persistence use getAt.

Using getAt() repeatedly on a the same list,  just for a bitwise validation, in loop, is one of worst things you can do

I hope you understand this

Now go back and look at your code the way you use getAt in a loop, BAD IS IT NOT?

SUMMING UP

Arrays are Fast, but limited regarding managing pc resources, empty elements use memory, declaring a 128 array and only using 2 elements [0][1] in total  is f*#@ing stupid has 

List are  versatile in this regard but slow has F U C K

If you look carefully at my code you will notice I only call individual list once in the loop, never call the same list twice. If you refactor my code, it is exactly the same as @xkkmEl only I use an Array for the formlist (hint) he use ten formlist properties 

YES GUYS I left out the head and tail, and heaps more,  this is just an introduction to list, and introduction to how they behave, not  a comprehensive guide or how to make one 

Let the attack begin OH opinionated ones with opinions, that nothing to say before I wrote this, however actual working knowledge that expands the information is most welcome, like

  1. what is the head and tail
  2. what advantage of singly over doubly linked list
  3. can doubly linked list do anything a singly list can't
  4. what is an ArrayList, (btw possible in vanilla, better with SKSE)
  5. etc

IF SOME ONE WANT CONTINUE WITH ADDING DATA TO THE LIST. EXPLAINING THE HEAD AND THE TAIL PLEASE DO

 

EDIT @csbx this should be a two hour lecture, with 100 slides, and same basic knowledge already, I hope I got the simple gist across, on how they behave  

Edit #2 @csbx in your loop you spin your loop backwards, but since Skyrim lists are singly linked , the Get AT function iterate (spins) the list Forwards.. can you see that now? You do not have have has much control as what you thought 😉😉 where I am deeply aware in my backward code it is spinning backwards ten times and the 10 list are spinning forward 100 - 200 times 

 

Link to comment
Share on other sites

Woh - just knocked out 40% of my code and things run exactly the same - Thanks to both of you !

I even tracked down a gargantuan ridiculous bit of code:

if SavedText[0] != CorrectReplacementText && SavedText[1] != CorrectReplacementText&& SavedText[2] != CorrectReplacementText && SavedText[3] != CorrectReplacementText && SavedText[4] != CorrectReplacementText && SavedText[5] != CorrectReplacementText && \
												SavedText[6] != CorrectReplacementText && SavedText[7] != CorrectReplacementText && SavedText[8] != CorrectReplacementText && SavedText[9] != CorrectReplacementText && SavedText[10] != CorrectReplacementText && SavedText[11] != CorrectReplacementText && \
												SavedText[12] != CorrectReplacementText && SavedText[13] != CorrectReplacementText && SavedText[14] != CorrectReplacementText && SavedText[15] != CorrectReplacementText && SavedText[16] != CorrectReplacementText && SavedText[17] != CorrectReplacementText && \
												SavedText[18] != CorrectReplacementText && SavedText[19] != CorrectReplacementText)

And replaced it with

if (SavedText.Find(CorrectReplacementText as String) < 0)

I knew about Find, but didn't seem to notice its obvious application here..

Peter - your posts are so thick I have to read a few times to take it in. It's great.  Really adds some depth to just why my initial code (just written to make work without worrying about efficiency) wasn't good enough. Thank you for your explanation.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...