csbx Posted June 10 Share Posted June 10 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 More sharing options...
xkkmEl Posted June 10 Share Posted June 10 (edited) 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 June 10 by xkkmEl Link to comment Share on other sites More sharing options...
PeterMartyr Posted June 10 Share Posted June 10 (edited) 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 June 11 by PeterMartyr Link to comment Share on other sites More sharing options...
PeterMartyr Posted June 10 Share Posted June 10 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 More sharing options...
PeterMartyr Posted June 11 Share Posted June 11 @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 declare a bigger temp Array Copy the Array over to the temp Array overwrite the original pointer with the new Array delete the temp Array to release the memory 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 list that singly linked (1 node) only go one direction forwards 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 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 what is the head and tail what advantage of singly over doubly linked list can doubly linked list do anything a singly list can't what is an ArrayList, (btw possible in vanilla, better with SKSE) 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 More sharing options...
PeterMartyr Posted June 11 Share Posted June 11 bottom line is list do not have indexes and never treat them like Arrays.. that asking for trouble, and code like that preforms like shite Link to comment Share on other sites More sharing options...
csbx Posted June 16 Author Share Posted June 16 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 More sharing options...
Recommended Posts