Find count of elements in a Vector - actionscript-3

If I assign a Vector like
var vec1:Vector.<Number> = new Vector.<Number>(3);
vec1 = (1,2);
the result of vec1.length is 3. Is there any built-in method to return the number of the elements actually present in the vector?
I'm an ActionScript noob so any help would be appreciated.

Well you can solve your problem by creating an empty vector instead of a defining the vector size at the time of its declaration and then you gradually add and remove elements to the vector. In this way you will always get the total number of elements inside the vector when you call vector.length
For example:
var vec1:Vector.<Number> = new Vector.<Number>();
vec1.push(5);
vec1.push(6,7);
vec1.pop();
Then vec1.length would give you 2.

Its been awhile, heres the reference: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Vector.html
I believe the .length is the normal way to check its length. If you want to check for "empty elements" you will need to loop through it with a loop.
I don't remmember the exact syntax, but to loop, do something like:
int count = 0;
for (int i = 0; i < vec.length; i++) {
if (vec[i] == ... );
count++;
}

Related

Under what circumstances is a reverse for loop faster in Flash and why?

According to Adobe, a reverse for loop is the fastest way to do a loop:
http://www.adobe.com/devnet/flash/articles/optimizing-flash-performance.html
I could not create a test where a reverse for loop was consistently faster than a normal loop, but I'm assuming Adobe knows Flash. Does anyone know under what circumstance this is true and why?
You don't have to recalculate the length of an array or Vector if you iterate backwards.
for(var i:int = list.length; i > 0; i--)
// -------------^^^^^^^^^^^ Length is calculated once for the start value.
Versus:
for(var i:int = 0; i < list.length; i++)
// --------------------^^^^^^^^^^^ Length is calculated for each iteration.
FYI, the difference is speed is negligible. I personally use whichever is more readable to me (the former).
That aside - if you are iterating over a collection where all objects are of the same type, you should be using a for each loop. This is much faster, more readable and more logical than either of the above. The reason that it is faster is because no type conversion is required at each iteration - the type is set when you define the loop:
var strings:Array = ["a","b","c"];
for each(var i:String in strings)
{
trace(i);
}
Marty is correct: if you use a reverse for loop you have to get the length value only once. However, this can be easily achieved through a normal for loop, and assigning the length to a variable beforehand.
A further optimized reverse for loop would look like:
for(var i:int = list.length; i--;)
which results in looping through every element in the array in reverse without a third for loop argument.

Using byteArray with getPixel (no 's') then setPixelS

Here is what I am trying to do:
one byteArray (colorsByteArray) holds color values, that I created with the "getPixels" method;
for every pixel on screen, I make calculations and depending on that I get a rank that I use to retrieve the proper color value inside colorsByteArray;
finally, I write inside a second byteArray (pixelsByteArray) the color I just retrieved. Then I 'draw' this byteArray using the "setPixels" method.
Problem is I do not find the same image as if I simply wrote a "setPixel" for every pixel in my loop. The image I get is missing one line out of two, and is kind of repeated three times horizontally. Of course I guess I must be writing (or reading) something wrong from my second byteArray, but can someone explain me what I am doing wrong? Or even if my efforts are worth anything actually :-) cause I didn't find anything quite like this so far...
Thanks!
Here is a bit of my code to make things clearer:
colorsByteArray = bitmDext.getPixels(new Rectangle(0, 0, myShadeBMD.width, 1));
canvas.lock();
for(var i:int = 0; i < STAGE_WIDTH; i++)
{
for(var j:int = 0; j < STAGE_HEIGHT; j++)
{
//make some calculation on each pixel to get the 'colorRank' uint value
colorsByteArray.position = colorRank * 4;//unsigned int is 32 bytes, representing 4 slots of a byteArray
var colorValue:uint = colorsByteArray.readUnsignedInt();
//canvas.setPixel(i, j, colorValue);//works just fine
pixelsByteArray.writeUnsignedInt(colorValue);
}
}
pixelsByteArray.position = 0;
var myRect:Rectangle = new Rectangle(0, 0, STAGE_WIDTH, STAGE_HEIGHT);
canvas.setPixels(myRect, pixelsByteArray);
canvas.unlock();
added a picture that may help:
http://www.oghel.com/pictures/stackOverflow/example3
the expected part is on the right, the wrong one on the left.

AS3 math: nearest neighbour in array

So let's say i have T, T = 1200. I also have A, A is an array that contains 1000s of entries and these are numerical entries that range from 1000-2000 but does not include an entry for 1200.
What's the fastest way of finding the nearest neighbour (closest value), let's say we ceil it, so it'll match 1201, not 1199 in A.
Note: this will be run on ENTER_FRAME.
Also note: A is static.
It is also very fast to use Vector.<int>instead of Arrayand do a simple for-loop:
var vector:Vector.<int> = new <int>[ 0,1,2, /*....*/ 2000];
function seekNextLower( searchNumber:int ) : int {
for (var i:int = vector.length-1; i >= 0; i--) {
if (vector[i] <= searchNumber) return vector[i];
}
}
function seekNextHigher( searchNumber:int ) : int {
for (var i:int = 0; i < vector.length; i++) {
if (vector[i] >= searchNumber) return vector[i];
}
}
Using any array methods will be more costly than iterating over Vector.<int> - it was optimized for exactly this kind of operation.
If you're looking to run this on every ENTER_FRAME event, you'll probably benefit from some extra optimization.
If you keep track of the entries when they are written to the array, you don't have to sort them.
For example, you'd have an array where T is the index, and it would have an object with an array with all the indexes of the A array that hold that value. you could also put the closest value's index as part of that object, so when you're retrieving this every frame, you only need to access that value, rather than search.
Of course this would only help if you read a lot more than you write, because recreating the object is quite expensive, so it really depends on use.
You might also want to look into linked lists, for certain operations they are quite a bit faster (slower on sort though)
You have to read each value, so the complexity will be linear. It's pretty much like finding the smallest int in an array.
var closestIndex:uint;
var closestDistance:uint = uint.MAX_VALUE;
var currentDistance:uint;
var arrayLength:uint = A.length;
for (var index:int = 0; index<arrayLength; index++)
{
currentDistance = Math.abs(T - A[index]);
if (currentDistance < closestDistance ||
(currentDistance == closestDistance && A[index] > T)) //between two values with the same distance, prefers the one larger than T
{
closestDistance = currentDistance;
closestIndex = index;
}
}
return T[closestIndex];
Since your array is sorted you could adapt a straightforward binary search (such as explained in this answer) to find the 'pivot' where the left-subdivision and the right-subdivision at a recursive step bracket the value you are 'searching' for.
Just a thought I had... Sort A (since its static you can just sort it once before you start), and then take a guess of what index to start guessing at (say A is length 100, you want 1200, 100*(200/1000) = 20) so guess starting at that guess, and then if A[guess] is higher than 1200, check the value at A[guess-1]. If it is still higher, keep going down until you find one that is higher and one that is lower. Once you find that determine what is closer. if your initial guess was too low, keep going up.
This won't be great and might not be the best performance wise, but it would be a lot better than checking every single value, and will work quite well if A is evenly spaced between 1000 and 2000.
Good luck!
public function nearestNumber(value:Number,list:Array):Number{
var currentNumber:Number = list[0];
for (var i:int = 0; i < list.length; i++) {
if (Math.abs(value - list[i]) < Math.abs(value - currentNumber)){
currentNumber = list[i];
}
}
return currentNumber;
}

adding items from an array multiple times to the stage

I have a for loop which passes 11 times:
private var currentItem:uint;
for(var i:uint = 0;i<10;i+){
addChild(arr[currentItem]);
currentItem++;
if(currentItem == arr.length){
currentItem = 0;
}
}
So the problem is that the array only contains 6 items. So when it comes to the 6th item the currentItem resets and the next 4 items that are getting added are the 4 first from the array again. Now when I trace the items, the last 4 trace "null". My question is, how can I add items from the array multiple times without losing its properties etc?
There's nothing inherently wrong with your loop. However, a DisplayObject can only be on the display list once. It can't have multiple parents or be a child of the same parent many times. That's why your code isn't working.
Update:
If you want to create new instances from a list of Classes you can do that, but your current approach wont work. This is what you need to do:
// the square bracket notation is shorthand for creating an array.
// fill the array with references to *classes* not instances
var classes:Array = [ MyClassOne, MyClassTwo, MyClassThree ];
// we run the loop much as you did, but we can make it much more compact
// by using the modulus operator
// since the array is full of classes, we can use the new operator to
// create new instances of those classes and add them to the display-list
for(var i:uint = 0; i < 10; i++ ){
addChild(new classes[i % classes.length]);
}

For-loop variable scope confusion

I have noticed a weird behavior of the variables in for loops. It's not really a problem, but it disturbs me a lot.
Actually I've created two loops this way:
for (var i:uint; i<19; i++) SomeFunction (i);
for (var i:uint; i<26; i++) SomeOtherFunction (i);
What I received was a compilation warning:
Warning: Duplicate variable definition.
This warning really surprised me. Nothing like that ever happened to me in other languages.
It seems that the i variable gets into the scope that is higher in the hierarchy and becomes available out of the loop's block. I've also tried to embrace the loop block in a curly brace, but it didn't change anything.
Why does it happen? Is it normal? Is it possible to avoid it? For now I've just set different names for both of the variables, but that's not a real solution I think. I'd really like to use the i-named variable in most of my for-loops.
yes, the loop increment variable is in the scope of the loops parent, not inside the loop itself. This is intentional, for examples like this:
public function getPositionOfValue ( value:String ) : int
{
for ( var i:int = 0; i < someArray; i++ )
{
if (someArray[i] == value )
{
break;
}
}
return i;
}
this allows you to access the value of i once the loop is over. There are lots of cases where this is very useful.
What you should do in the cases where you have multiple loops inside the same scope is var the i outside of the loops:
public function getPositionOfValue ( value:String ) : int
{
var i:int;
for ( i = 0; i < 15; i++ )
{
//do something
}
for ( i = 0; i < 29; i++ )
{
//do something else
}
return i;
}
then you get rid of your warning. The other thing to consider is to name your loop increment variables something more descriptive.
Update: Two other things to consider:
1) you shouldn't use uints except for things like colors and places where Flex expects a uint. They are slower than int's to use. Source]1 Update: it looks like this may no longer be the case in newer versions of the flash player: source
2) when you var a loop increment variable inside of a loop declaration, you want to make sure you set it to the proper initialization value, usually 0. You can get some hard to track down bugs if you dont.
As mentioned here, as3 has global and local scope and that's about it.
It does not do block-level scoping (or for-level either). With hoisting, you can even write to variables before you define them. That's the bit that would do my head in :-)
Early versions of Visual C had this bug, leading to all sorts of wonderful funky macro workarounds but this is not a bug in as3, it's working as designed. You can either restrict your code to having the declaration in the first for only or move the declaration outside all the for statements.
Either way, it's a matter of accepting that the language works one way, even though you may think that's a bad way :-)
Declare the variable i outside the loops to avoid this. As long as you reset it (i=0) you can still use it in all loops.
var i : uint;
for (i=0; i<19; i++) SomeFunction(i);
for (i=0; i<26; i++) SomeOtherFunction(i);