[ExampleResource]General-purpose Array Functions

Post » Wed Jun 20, 2012 10:32 pm

Due to http://www.gamesas.com/topic/1365445-bug-formlist-functions-seem-to-break-under-certain-conditions/, I decided to convert the functionality over to arrays. In the process, I needed to write some general-use array manipulation functions to save myself some work. Here they are! Feel free to use them.

These functions were primarily designed to be anologous to using FormList functions, just with arrays. You won't be able to use these with integers or floats without some re-work.

Also please suggest if it looks like something could be done better, or if I made a mistake. The names are similar to the FormList functions, to avoid confusion as to their purpose.

All of the examples use a generic input parameter of type Form, but you will need to change the type of the array input parameter / form to the type of array / forms you're using, or perhaps call it "as Form" (though I haven't tested it this way).

Enjoy :geek:

bool function ArrayAddForm(Form[] myArray, Form myForm)
Adds a form to the first available element in the array.
Spoiler

bool function ArrayAddForm(Form[] myArray, Form myForm)	;-----------\	;Description \	Author: Chesko	;----------------------------------------------------------------	;Adds a form to the first available element in the array.		;-------------\	;Return Values \	;----------------------------------------------------------------	;		false		=		Error (array full)	;		true		=		Success				int i = 0	;notification("myArray.Length = " + myArray.Length)	while i < myArray.Length		if myArray[i] == none			myArray[i] = myForm			;notification("Adding " + myForm + " to the array.")			return true		else			i += 1		endif	endWhile		return falseendFunction

bool function ArrayRemoveForm(Form[] myArray, Form myForm, bool bSort = false)
Removes a form from the array, if found. Sorts the array using ArraySort() if bSort is true.
Spoiler

bool function ArrayRemoveForm(Form[] myArray, Form myForm, bool bSort = false)		;-----------\	;Description \	Author: Chesko	;----------------------------------------------------------------	;Removes a form from the array, if found. Sorts the array using ArraySort() if bSort is true.		;-------------\	;Return Values \	;----------------------------------------------------------------	;		false		=		Error (Form not found)	;		true		=		Success	int i = 0	while i < myArray.Length		if myArray[i] == myForm			myArray[i] = none			;notification("Removing element " + i)			if bSort == true				ArraySort(myArray)			endif			return true		else			i += 1		endif	endWhile		return false	endFunction
Example:
ArrayRemoveForm(myWeaponArray, myWeapon as Form)	;Removes myWeapon from myWeaponArray, if found.ArrayRemoveForm(myArmorArray, myArmor as Form, true)	;Removes myArmor from myArmorArray if found, and re-sorts the the array (makes all data contiguous)

bool function ArraySort(Form[] myArray, int i = 0)
Removes blank elements by shifting all elements down.
Spoiler

bool function ArraySort(Form[] myArray, Int i = 0)	 ;-----------\	 ;Description \  Author: Chesko	 ;----------------------------------------------------------------	 ;Removes blank elements by shifting all elements down.	 ;Optionally starts sorting from element i.	 ;-------------\	 ;Return Values \	 ;----------------------------------------------------------------	 ;		   false		   =			   No sorting required	 ;		   true			=			   Success	 bool bFirstNoneFound = false	 int iFirstNonePos = i	 while i < myArray.Length		  if myArray[i] == none			   if bFirstNoneFound == false					bFirstNoneFound = true					iFirstNonePos = i					i += 1               else                    i += 1			   endif		  else			   if bFirstNoneFound == true			   ;check to see if it's a couple of blank entries in a row					if !(myArray[i] == none)						 ;notification("Moving element " + i + " to index " + iFirstNonePos)						 myArray[iFirstNonePos] = myArray[i]						 myArray[i] = none									 ;Call this function recursively until it returns						 ArraySort(myArray, iFirstNonePos + 1)						 return true					else						 i += 1					endif			   else					i += 1			   endif		  endif	 endWhile	 return falseendFunction

function ArrayClear(Form[] myArray)
Deletes the contents of this array.
Spoiler

function ArrayClear(Form[] myArray)	;-----------\	;Description \	Author: Chesko	;----------------------------------------------------------------	;Deletes the contents of this array.	;-------------\	;Return Values \	;----------------------------------------------------------------	;		none	int i = 0	while i < myArray.Length		myArray[i] = none		i += 1	endWhileendFunction

int function ArrayCount(Form[] myArray)
Counts the number of indices in this array that do not have a "none" type.
Spoiler

int function ArrayCount(Form[] myArray)	;-----------\	;Description \	Author: Chesko	;----------------------------------------------------------------	;Counts the number of indices in this array that do not have a "none" type.	;-------------\	;Return Values \	;----------------------------------------------------------------	;		int myCount = number of indicies that are not "none"	int i = 0	int myCount = 0	while i < myArray.Length		if myArray[i] != none			myCount += 1			i += 1		else			i += 1		endif	endWhile	;notification("MyCount = " + myCount)		return myCountendFunction

int function ArrayHasForm(Form[] myArray, Form myForm)
Attempts to find the given form in the given array, and returns the index of the form if found.
Spoiler

int function ArrayHasForm(Form[] myArray, Form myForm)	;-----------\	;Description \	Author: Chesko	;----------------------------------------------------------------	;Attempts to find the given form in the given array, and returns the index of the form if found.	;-------------\	;Return Values \	;----------------------------------------------------------------	;		-1		  =		Form not found	;		int i		  =		Location of the form	int i = 0	while i < myArray.Length		if myArray[i] == myForm			return i		else			i += 1		endif	endWhile	return -1endFunction
User avatar
Katie Pollard
 
Posts: 3460
Joined: Thu Nov 09, 2006 11:23 pm

Post » Wed Jun 20, 2012 11:41 pm

I'm having trouble with this example on your sort. Say we have the array

{1,2,3,none,none,4,5}

in your code, this happens:
	    while i < myArray.Length	    // i starts at 0			    if myArray[i] == none	  //myArray[0] == 1, this is false					    if bFirstNoneFound == false							    bFirstNoneFound = true							    iFirstNonePos = i							    i += 1					    endif			    else					    if bFirstNoneFound == true //this is also false							    ;notification("Moving element " + i + " to index " + iFirstNonePos)							    myArray[iFirstNonePos] = myArray[i]							    myArray[i] = none							   							    ;Call this function recursively until it returns							    ArraySort(myArray)							    return true					    endif			    endif  //i == 0 here, so we do this over and over	    endWhile


Also in your removeForm method:

  if myArray[i] == myForm	   myArray[i] == none	   ;notification("Removing element " + i)		if bSort == true			   ArraySort(myArray)		 endif		 return true		 ...

the line myArray[i] == none

is the equality operator, nothing is assigned -- might want to fix that I thnk
User avatar
Britta Gronkowski
 
Posts: 3475
Joined: Mon Apr 09, 2007 3:14 pm

Post » Wed Jun 20, 2012 3:08 pm

Suggested changes to the ArraySort function:

Spoiler
bool function ArraySort(Form[] myArray, Int i = 0)	;-----------\	;Description \  Author: Chesko	;----------------------------------------------------------------	;Removes blank elements by shifting all elements down.	;Optionally starts sorting from element i.	;-------------\	;Return Values \	;----------------------------------------------------------------	;			false			=			No sorting required	;			true			=			Success	bool bFirstNoneFound = false		int iFirstNonePos = i		while i < myArray.Length			if myArray[i] == none				if bFirstNoneFound == false					bFirstNoneFound = true					iFirstNonePos = i					i += 1				endif			else				if bFirstNoneFound == true					;check to see if it's a couple of blank entries in a row					if !(myArray[i] == none)						;notification("Moving element " + i + " to index " + iFirstNonePos)						myArray[iFirstNonePos] = myArray[i]						myArray[i] = none						;Call this function recursively until it returns						ArraySort(myArray, iFirstNonePos + 1)						return true					else						i += 1					endif				endif			endif		endWhile		return falseendFunction

EDIT:

@oceans

I doubt that any of the functions can be adapted to int or float arrays, unless you initialize all your arrays to some default value like -187293 and substitute that in for 'none' in all the functions.
User avatar
JaNnatul Naimah
 
Posts: 3455
Joined: Fri Jun 23, 2006 8:33 am

Post » Wed Jun 20, 2012 10:15 pm

Brilliant RandomNoob, thank you. I'll update the OP.

And sorry if I wasn't clear; these functions were mainly designed to be anologous to using FormLists (with Form types), not integers or floats.

Edit: Fixed the equality operator in ArrayRemoveForm() in the OP. Thanks oceans.
User avatar
Marie Maillos
 
Posts: 3403
Joined: Wed Mar 21, 2007 4:39 pm

Post » Wed Jun 20, 2012 2:23 pm

Suggested changes to the ArraySort function:

Spoiler
bool function ArraySort(Form[] myArray, Int i = 0)	;-----------\	;Description \  Author: Chesko	;----------------------------------------------------------------	;Removes blank elements by shifting all elements down.	;Optionally starts sorting from element i.	;-------------\	;Return Values \	;----------------------------------------------------------------	;			false			=			No sorting required	;			true			=			Success	bool bFirstNoneFound = false		int iFirstNonePos = i		while i < myArray.Length			if myArray[i] == none				if bFirstNoneFound == false					bFirstNoneFound = true					iFirstNonePos = i					i += 1				endif			else				if bFirstNoneFound == true					;check to see if it's a couple of blank entries in a row					if !(myArray[i] == none)						;notification("Moving element " + i + " to index " + iFirstNonePos)						myArray[iFirstNonePos] = myArray[i]						myArray[i] = none						;Call this function recursively until it returns						ArraySort(myArray, iFirstNonePos + 1)						return true					else						i += 1					endif				endif			endif		endWhile		return falseendFunction

EDIT:

@oceans

I doubt that any of the functions can be adapted to int or float arrays, unless you initialize all your arrays to some default value like -187293 and substitute that in for 'none' in all the functions.

I wasn't using ints, it was a simple example about a flaw in the original array (which you pointed out also) . The {1,2,3 .. } were just elements in the array. THey just were elements that supported the == operator and used his algorithm for sorting.


Also this is directed to OP:

Since you allow the user to incur the cost of sorting, you should allow the user the benefits of a sorted data structure. Currently, the addForm runs in O(n) time by going through the list for the first non none element even if the list is sorted. If it is sorted you only need to append it to the end, this can be done in O(1) time. Getting the number of elements can also be done in constant time if it is sorted. I think you should implement a flag (or an add an input to the functions that allow the user to tell the function that the array is sorted) and so if it is a sorted array you do not go into a loop.
User avatar
Melung Chan
 
Posts: 3340
Joined: Sun Jun 24, 2007 4:15 am

Post » Wed Jun 20, 2012 11:43 am

@oceans - How do I "know" which element number is the top-most (the first "none" type element) to put data in without walking the array first? Wouldn't I have to store the index pointing to the top of the stack in a separate variable somewhere? Are you saying, "Allow the user to manually specify the index to add the form to as an optional parameter"?
User avatar
bimsy
 
Posts: 3541
Joined: Wed Oct 11, 2006 3:04 pm

Post » Wed Jun 20, 2012 8:49 pm

@oceans

Sorry, I misunderstood you.

@Chesko

I think that oceans means that you should add an optional parameter to the functions allowing the user to specify if the array has been sorted, so that it stops walking the array at the first 'none' element.

Example:

Spoiler
int function ArrayHasForm(Form[] myArray, Form myForm, Bool bSorted = False, Int N = -1)	;-----------\	;Description \  Author: Chesko	;----------------------------------------------------------------	;Attempts to find the given form in the given array, and returns the index of the form if found.	;Optionally specify whether or not the array has been sorted ('None' elements removed)	;Optionally stops searching at the Nth element.	;-------------\	;Return Values \	;----------------------------------------------------------------	;			-1		=			Form not found	;			int i		=			Location of the form	int i = 0	if (N == -1)		N = MyArray.Length	endif	if (Sorted)		while (i < N && myArray[i] != None)			if myArray[i] == myForm				return i			else				i += 1			endif		endWhile	else		while (i < N)			if myArray[i] == myForm				return i			else				i += 1			endif		endWhile	endif		return -1endFunction

And my suggestion for a new function, not sure if it's any good as I haven't tested it:

Spoiler
Bool Function ArrayRemoveDuplicates(Form[] MyArray, Bool bSorted = False)	Form[] TempArray = new Form[128]		int i = 0	int j = 0		if (bSorted)		while (i < MyArray.Length && MyArray[i] != None)			if (ArrayHasForm(TempArray, MyArray[i], bSorted, j) < 0)				TempArray[j] = MyArray[i]				j += 1			endif			i += 1		endwhile	else		while (i < MyArray.Length)			if (ArrayHasForm(TempArray, MyArray[i], j) < 0)				TempArray[j] = MyArray[i]				j += 1			endif			i += 1		endwhile	endif		if (i > j)		i = 0		while (TempArray[i] != TempArray[i + 1])			MyArray[i] = TempArray[i]			i += 1		endwhile		while (i < MyArray.Length)			MyArray[i] = None			i += 1		endwhile		Return True	endif		Return False	EndFunction


EDIT:
Was looking through this thread again and realized that what I suggested for the ArraySort function didn't address the problems raised by oceans.

Spoiler
bool function ArraySort(Form[] myArray, Int i = 0)    ;-----------\    ;Description \    ;----------------------------------------------------------------    ;Removes blank elements by shifting all elements down.    ;Optionally starts sorting from element i.    ;-------------\    ;Return Values \    ;----------------------------------------------------------------    ;        false        =        No sorting required    ;        true        =        Success    int iFirstNonePos = -1    while (i < myArray.Length)        if (myArray[i] == none)            if (iFirstNonePos < 0)                iFirstNonePos = i            endif        elseif (iFirstNonePos >= 0)            ;notification("Moving element " + i + " to index " + iFirstNonePos)            myArray[iFirstNonePos] = myArray[i]            myArray[i] = none            ;Call this function recursively until it returns            ArraySort(myArray, iFirstNonePos + 1)            return true        endif        i += 1    endWhile    return falseendFunction
User avatar
Vera Maslar
 
Posts: 3468
Joined: Wed Sep 27, 2006 2:32 pm

Post » Wed Jun 20, 2012 5:32 pm

Thanks for this Chesko, I freaking hate formlists by now, I had the same issues you had (and then some) and was about to give up on my ideas. Hopefully i'll be able to make something out of this. This is my last shot before GW2 XD
User avatar
rebecca moody
 
Posts: 3430
Joined: Mon Mar 05, 2007 3:01 pm

Post » Wed Jun 20, 2012 4:37 pm

Hey Chesko, think I should wait before using these, like wait for improvements, or are they good to go?

Also, is there a maximum length for arrays? What about form lists and leveled lists? I know it's unrelated to your topic but I'm using those too, would appreciate the answer (:

Again, thanks for this
User avatar
Lynne Hinton
 
Posts: 3388
Joined: Wed Nov 15, 2006 4:24 am

Post » Thu Jun 21, 2012 2:59 am

The maximum length for arrays is 128. About Form Lists and Leveled Lists, i don't know if there's a limit. But if you're still using these two and have issues with them, you should use arrays instead, because they are really safe.
User avatar
Stephanie Valentine
 
Posts: 3281
Joined: Wed Jun 28, 2006 2:09 pm

Post » Wed Jun 20, 2012 8:03 pm

ArcaneSmith - Sorry for the late reply. I am currently using these functions in Frostfall without fail, so it should be safe.

Error handling is the only thing I could think of that could be improved.
User avatar
Chica Cheve
 
Posts: 3411
Joined: Sun Aug 27, 2006 10:42 pm

Post » Wed Jun 20, 2012 2:10 pm

Alright, i'm already finishing this project for Lorecraft using them and it's been working flawlessly. I'm sure all ideas i had before that were limited by buggy formlists will be dealt with now, thanks again for sharing =)
User avatar
Valerie Marie
 
Posts: 3451
Joined: Wed Aug 15, 2007 10:29 am

Post » Wed Jun 20, 2012 6:14 pm

Updated ArraySort to prevent an infinite loop. Sorry for the jacked up indentation formatting, I can't seem to fix it. Copy/paste into a text editor to make more sense out of it.

Edit: Fixed another one. It should now properly handle an array that can potentially be blank.
User avatar
gandalf
 
Posts: 3400
Joined: Wed Feb 21, 2007 6:57 pm

Post » Wed Jun 20, 2012 6:26 pm

Hello there!
Anybody knows, how to get by script an array of all equipped on Player objects?
User avatar
Amy Masters
 
Posts: 3277
Joined: Thu Jun 22, 2006 10:26 am

Post » Wed Jun 20, 2012 1:31 pm

Hello there!
Anybody knows, how to get by script an array of all equipped on Player objects?

This will return a 32 element array, which will probably have some empty elements at the end (requires SKSE):

Form[] Function SaveOutfit(Actor akActor)	Form[] SavedOutfit = new Form[32]	int slot = 1	int i	int j	while (i < 32)		Form TempForm = akActor.GetWornForm(slot)		if (TempForm)			SavedOutfit[j] = TempForm			j += 1		endif		slot *= 2		i += 1	endwhile	Return SavedOutfitEndFunction

EDIT: Forgot to mention that I think there would be duplicates if a piece of equipment takes up multiple slots. You'd have to adjust the code so that it reiterates the array for each check in order to find whether or not the equipped item has already been saved to the array.
User avatar
Bereket Fekadu
 
Posts: 3421
Joined: Thu Jul 12, 2007 10:41 pm

Post » Wed Jun 20, 2012 6:19 pm

RandomNoob, thanks!
What version of SKSE have this function? (I mean, only last betas, or the stable ver. for patch 1.5.26 too ?)
to find whether or not the equipped item has already been saved to the array
no problem.
User avatar
FLYBOYLEAK
 
Posts: 3440
Joined: Tue Oct 30, 2007 6:41 am

Post » Wed Jun 20, 2012 10:48 pm

Sorry, don't remember which one exactly, but you can use it since version 1.5.6.
User avatar
Emilie Joseph
 
Posts: 3387
Joined: Thu Mar 15, 2007 6:28 am

Post » Wed Jun 20, 2012 2:55 pm

Using ArrayHasForm in first post, we can check this like:
Spoiler
;in code above, before adding an element - check existing array for it...		if (TempForm)			if ArrayHasForm(SavedOutfit,TempForm) == -1				SavedOutfit[j] = TempForm				j += 1			endif		endif...

Thank you :yes:
User avatar
Niisha
 
Posts: 3393
Joined: Fri Sep 15, 2006 2:54 am

Post » Wed Jun 20, 2012 8:43 pm

Looks like there are some http://www.creationkit.com/Arrays_(Papyrus)#Searching_Arrays with Skyrim 1.6.
User avatar
Kayla Oatney
 
Posts: 3472
Joined: Sat Jan 20, 2007 9:02 pm


Return to V - Skyrim