as3 ARRAY SHIFT - the End of array now what? - arrays

I am having the alphabet go on and off screen. I am using the array SHIFT to do this to go to the next letter. When I get to the last element of the array, the letter Z, how can I go to the beginning?
Another example would be if you had an array of pictures and after you are done viewing the last one the code would take you to the begining again and you start viewing from there.
Here is the code where I need to set the shift back to zero.
var Letter:MovieClip;
function fl_MouseClickHandler_2(event:MouseEvent):void
{
if(Letter)
{
var gone:MovieClip = Letter as MovieClip;
TweenMax.to(Letter, 1, { x:0 , ease:Back.easeOut, onComplete:removeLetter});
function removeLetter(){
removeChild(gone);
}
}
if(Alphabet.length!=0)
{
Letter = new alphabetLetter();
addChild(Letter);
/// THIS KEY CODE LINE THAT USES SHIFT
Letter.letter.text = Alphabet.shift();
TweenMax.fromTo(Letter, 2, {x:stage.stageWidth}, {x:stage.stageWidth/2-Letter.width, ease:Expo.easeOut});
}
else
{
//// TRIED THIS BUT DOES NOT WORK
Alphabet.unshift(27);
}
/// WHAT CODE DO I USE HERE TO SET THE ARRAY BACK TO THE BEGINNING?
if(Alphabet.length==0)
{
Alphabet.shift = 0; /// ???
}

shift() removes an element from an array so you cannot get it back unless you keep it somewhere else to put it back in the array when you need it again.
You had better just use an index variable to find the right element in the array without actually modifying it: then if your index value is larger than 26, start at 0 again.
Or, use push() to put the letter back at the end of the array immediately after shifting. That way your array never gets empty.

Related

Is it safe to iterate an array while modifying it?

I know you shouldn't, I kind of know why. But I mean I don't understand my own code once I am trying really to think what's going on.
So I have an array with bunch of objects. I am iterating over it and once I find an object with specific type, I remove it from the array, and add another object into the array. So something like this:
var arr = parent.allchildren() //getting all the children in array
for ele in arr{
if(ele==somethingHere){
parent.remove(ele)
parent.add(new ele) //add new child into child array
}
}
If I have an array of 1,2,3,4,5, and I remove 3 and add a 6 while iterating, the actual array would be 1,2,4,5,6 but the array I am iterating would still be 1,2,3,4,5.
Which I think it would be fine, because at the end I still get what I want, which removed the element and added the element I need. However modifying the list while iterating it is bad and you shouldn't do that, but for my case I think it does what I need. What could be the potential issue in my case that I can't see?
One thing you may want to think about doing is making all of the changes at the end of the iteration. Instead of making the changes one by one, record the changes you want to make while iterating, and then actually make those changes once your loop is finished.
For example, you could make an array of elements to remove, and an array of elements to add.
//Our array where we record what we want to add
var elementsToAdd = [Any]()
//Our array of what elements we want to remove. We record the index at
//which we want to remove the element from the array
var indexesToRemoveAt = [Int]()
//Getting all the children in array
var arr = parent.allchildren()
//Enumerating an array allows us to access the index at which that
//element occurs. For example, the first element's index would be 0,
//the second element's index would be 1, the third would be 2, and so
//on
for (index,ele) in arr.enumerated() {
if(ele == somethingHere) {
indexesToRemoveAt.append(index)
elementsToAdd.append(newEle)
}
}
//Now that we have recorded the changes we want to make, we could make
//all of the changes at once
arr.remove(at: indexesToRemoveAt)
arr.append(contentsOf: elementsToAdd)
Note that removing array elements at multiple indexes would require the following extension to Array. If you wanted to avoid creating this extension, you could always just loop through the array of indexes and tell the array to remove at each individual index. All this extension function is really doing is looping through the indexes, and removing the array element at said index.
Array extension to remove elements at multiple indexes:
extension Array {
//Allows us to remove at multiple indexes instead of just one
mutating func remove(at indexes: [Int]) {
for index in indexes.sorted(by: >) {
if index <= count-1 {
remove(at: index)
}
}
}
}
I just tested in a playground with the following code:
var arr = ["hi", "bye", "guy", "fry", "sky"]
for a in arr {
if arr.count >= 3 {
arr.remove(at: 2)
}
print(a)
}
print(arr)
This prints:
hi
bye
guy
fry
sky
["hi", "bye"]
So it looks like when you use a for-in loop in Swift, the array is copied and changes you make to it will not affect the array you are iterating over. To answer your question, as long as you understand that this is the behavior, there's nothing wrong with doing this.

Recursive function not breaking

I want to iterate over a 2D array and make subarrays whenever I find a different value in a specific column. Example:
TEST <----- This value should be ignored. Start counting at index 1.
A
A
A
-------- split here --------
B
B
B
-------- split here --------
C
-------- split here --------
This results in 3 arrays.
array1: [A,A,A]
array2: [B,B,B]
array3: [C]
My solution to this problem was a recursive method which takes the 2D array:
static func splitArray(fromArray array: [[String]], startIndex: Int = 1) {
for x in startIndex..<array.count {
if array.indices.contains(x+1) {
if (array[x][7]) != array[x+1][7] {
splitArray(fromArray: array, startIndex: x+1)
}
} else {
break
}
}
}
In this method I do the following:
Go through the array starting at index 1.
Compare the current index with the next index. If the next index has a different value split the array if not resume iterating.
To prevent array out of bounds I check if there's a next index - if there is no next index break the method (which should be called once the whole array has been iterated over)
Extra info:
The magic number 7 is the column in my 2D array I want to iterate over.
The method does reach the break command .. but somehow it jumps back in the method although it doesn't get called by the recursive splitArray call.
This method doesn't create the subarrays yet since the logic at this point is broken.
Why doesn't my function break? It does do its work - it splits correctly but then it starts over when it shouldn't.
P.S: If there's any coding advice I'd highly appreciate it, I feel this code in general is bad.
Solved it:
static func split(_ array: [[String]], startIndex: Int = 1) {
for x in startIndex..<array.count {
if array.indices.contains(x+1) {
if (array[x][7]) != array[x+1][7] {
split(array, startIndex: x+1)
break
}
}
}
}
The "fix" was to include the break after calling the recursive function. I guess the for loop resumed after calling split.

Why does this simple array access not work in Swift?

var word = "morning"
var arr = Array(word)
for s in 0...word.count {
print(arr[s])
}
This will not print. Of course, if I substitute a number for s, the code works fine.
Why will it not accept a variable in the array access braces? Is this peculiar to Swift?
I've spent a long time trying to figure this out, and it's nothing to do with s being optional.
Anyone understand this?
you are using inclusive range ... instead of ..<, so s goes from 0 to 7, not 0 to 6.
However, in arr the index goes from 0 to 6 because there are 7 characters.
Thus, when the program tries to access arr[7], it throws an index out of range error.
If you were coding on Xcode, the debugger would have told you that there is no arr[7].
As for the code, here is a better way to print every item in arr than using an index counter:
var word = "morning"
var arr = Array(word)
for s in arr {
print(s)
}
This is called a "foreach loop", for each item in arr, it assigns it to s, performs the code in the loop, and moves on to the next item, assigns it to s, and so on.
When you have to access every element in an array or a collection, foreach loop is generally considered to be a more elegant way to do so, unless you need to store the index of a certain item during the loop, in which case the only option is the range-based for loop (which you are using).
Happy coding!
When I run it, it prints the array then throws the error Fatal error: Index out of range. To fix this, change the for loop to:
for s in 0..<word.count {
print(arr[s])
}
try this
when you use a word to recognize
size of Array your Array index start as 0 so array last index must be equal with your (word.count - 1)
var word = "morning"
var arr = Array(word)
for s in 0...(word.count-1) {
print(arr[s])
}
Basically avoid index based for loops as much as possible.
To print each character of a string simply use
var word = "morning"
for s in word { // in Swift 3 word.characters
print(s)
}
To solve the index issue you have to use the half-open range operator ..< since indexes are zero-based.

Arrays not filling properly AS3

I wrote an array, where, when a hittest occurs, a number should be pushed into the array. However, when I use myArray.push, it enters the number, and when i call myArray.push again, instead of entering the number again and having 2 numbers in my array, it just enters the number in the same spot. So, if i use trace(myArray.length), no matter how many times it has pushed, it keeps saying I have 1 number stored.
This is my code:
if (hitTestObject(target.hit)) {
//pushes a number into an array
myArray.push();
//checks array length
if (myArray.length == 3) {
//do stuff
}
}
I've tried numbers, strings, and Math.random() in the parameters for myArray.push(), but I always get the same result of only having 1 item in my array.
For reference, this is how I wrote my variable for it:
public var myArray:Array = new Array();
You have to push something into the array. Try:
myArray.push(myArray.length);
However, it looks like you'd be better off just incrementing a number rather than creating an array. An array is a container of objects to be later referenced. So, unless you need to track that the third object in the array is in fact '2'...the array is useless. Try creating a number and increment the variable each time. Like this:
// Declared outside of the function
var integer:int = 0;
//
if (hitTestObject(target.hit)) {
integer = integer + 1;
// likewise you could use ++integer or integer++;
if (integer == 3) {
//do stuff
}
}
Based on your code, you are not actually pushing anything into the array.
The correct syntax is :
myArray.push(something);

How can i splice current index in a foreach?

I have this foreach loop to check for collision and i want platform(movieclip) to be removed in case of collision. So far i've come up with this:
if (mcContent.mcPlayer.y + mcContent.mcPlayer.height > platformCloud.y)
{
mcContent.mcPlayer.y = platformCloud.y - mcContent.mcPlayer.height - 1;
jump();
mcContent.removeChild(platformCloud);
//platformsCloud.splice(platformCloud);
}
What this is doing is, removing the movieclip (ok so far so good) but without the splice, when the loop runs again through the array it is still there. So with the splice that is commented out there's 1 little problem, it removes all the movieclips from the array, apprently.
How can i splice only the current index that is being checked?
.splice() accepts a start index and an amount of items to remove, not the object you want to remove from the array.
Parameters
startIndex:int — An integer that specifies the index of the element in the array where the insertion or deletion begins. You can use a negative integer to specify a position relative to the end of the array (for example, -1 is the last element of the array).
deleteCount:uint — An integer that specifies the number of elements to be deleted. This number includes the element specified in the startIndex parameter. If you do not specify a value for the deleteCount parameter, the method deletes all of the values from the startIndex element to the last element in the array. If the value is 0, no elements are deleted.
You want to do this:
var index:int = platformsCloud.indexOf(platformCloud);
platformsCloud.splice(index, 1);
Why not just create a new array of the items to keep? Use Array.push to add new items. This may actually be more efficient than modifying the existing array. It also doesn't require keeping track of indices (which are required to use Array.splice).
Example code:
var keptPlatforms = [];
// do stuff
if (mcContent.mcPlayer.y + mcContent.mcPlayer.height > platformCloud.y)
{
mcContent.mcPlayer.y = platformCloud.y - mcContent.mcPlayer.height - 1;
jump();
mcContent.removeChild(platformCloud);
} else {
keptPlatforms.push(platformCloud);
}
// later, after this cycle, use the new Array
platformClouds = keptPlatforms;
Now, the reason platformsCloud.splice(platformCloud) removes all items is because the first argument is coerced to an integer so it is equivalent to platformsCloud.splice(0) which says "remove the 0th-indexed item to the end of the array". And, this does indeed clear the array.
To use Array.splice, you'd have to do something like:
// inside a loop this approach may lead to O(n^2) performance
var i = platformClouds.indexOf(platformCloud);
if (i >= 0) {
platformClouds.splice(i, 1); // remove 1 item at the i'th index
}

Resources