Can generic list utilities use Vectors (AS3)? - arrays

Using Object or * as a type for a Vector doesn't provide generic functionality (like List in Java). Witness:
public static function someGenericVectorUtil (value:Vector.<*>) :void {
// do stuff to/with the Vector
}
var someVector:Vector.<Number>;
someGenericVectorUtil(someVector); // compile-time implicit coercion error
So, perhaps we redefine the utility method to accept an Array. But there's no easy way to convert Vectors going into the utility to Arrays, nor an easy way to pack them back in afterwards, resulting in code like this:
public static function someGenericArrayUtil (value:Array) :void {
// do stuff to/with the formerly-known-as-Vector
}
var someVector:Vector.<Number>;
var tempArray:Array = new Array(someVector.length);
for (var i:uint=0; i<someVector.length; i++) {
tempArray[i] = someVector[i];
}
someGenericVectorUtil(tempArray);
someVector = Vector.<Number>([tempArray]);
Needless to say, that's pretty hideous. Okay, so let's move the Vector-Array-Vector nonsense into a utility:
public static function vectorToArray (Vector.<*>) :Array {
// oh wait....that Vector.<*> param is useless,
// as demonstrated earlier.
}
Any way to straighten out this mess? Or should I just stop using Vectors when I think I might need to run them through generic utilities? (Obviously, also not really much of an option...)

public static function someGenericVectorUtil (value:Vector.<*>) :void {
// do stuff to/with the Vector
}
var someVector:Vector.<Number>;
someGenericVectorUtil(Vector.<*>(someVector));
^ it works. Also try with Array.

This is not an answer but more a long comment to #Lukasz's answer.
The problem with his answer is that you're actually creating a new Vector, so you need to return the Vector from someGenericVectorUtil and re-cast it. E.g. try:
var v:Vector.<int> = Vector.<int>([1,2,3]);
trace( v == Vector.<int>( Vector.<*>( v ) ) ); // traces false
That code just creates a simple Vector of ints, then compares it with a version of itself casted (first to *, then back to int). If you trace the Vectors out, they'll trace identical, but the actual Vectors references themselves aren't the same object. Thus if you have a utility function that modifies the Vector (e.g. a shuffle or randomise function), nothing will change.
E.g:
var v:Vector.<int> = Vector.<int>([1,2,3]);
trace( v ); // traces "1,2,3"
// shuffle() randomises the elements in a vector - this first call won't work
// as the cast creates a new vector
VectorUtil.shuffle( Vector.<*>( v ) );
trace( v ); // traces "1,2,3"
// we need to recast it back, and change shuffle() to return the vector
v = Vector.<int>( VectorUtil.shuffle( Vector.<*>( v ) ) );
trace( v ); // traces "3,1,2"
As you can see, it starts to get a bit ugly towards the end, and if you're keeping track of the Vector anywhere else, you'll need to update the references, but it's the only solution that I've found so far :S

Related

Map modify array of objects in Swift 2.2 (3.0)

I want to be able to modify my array of objects using map in Swift of the fly, without looping through each element.
Before here were able to do something like this (Described in more details here:
gnomes = gnomes.map { (var gnome: Gnome) -> Gnome in
gnome.age = 140
return gnome
}
Thanks for Erica Sadun and others, new proposals have gone through and we're now getting rid of C-style loops and using var inside the loop.
In my case I'm first getting a warning to remove the var in then an error my gnome is a constant (naturally)
My question is : How do we alter arrays inside a map or the new styled loops for that matter to be fully prepared for Swift 3.0?
If you want to keep that syntax, just use a (mutable) temporary variable
gnomes = gnomes.map { (gnome: Gnome) -> Gnome in
var mutableGnome = gnome
mutableGnome.age = 140
return mutableGnome
}
(Below follows the case where Gnome is a reference type; a class -- since you haven't showed us how you've defined Gnome. For the case where Gnome as value type (a struct), see #vadian:s answer)
The removal of var will not effect using .map to mutate mutable members of an array of reference type objects. I.e., you could simply use your old approach (omitting however, the var in the .map closure signature).
class Gnome {
var age = 42
}
var gnomes = [Gnome(), Gnome(), Gnome()]
gnomes = gnomes.map {
$0.age = 150
return $0
}
/* result */
gnomes.forEach { print($0.age) } // 3x 150
However, in case you just want to modify your original array rather than assigning the result of .map to a new array, .forEach might be a more appropriate choice than .map.
gnomes.forEach { $0.age = 140 }
/* result */
gnomes.forEach { print($0.age) } // 3x 140
Given:
struct Gnome {
var age: Int = 0
}
var gnomes = Array(count: 5, repeatedValue: Gnome())
... there are two decent options. The first is as #vadian put it:
gnomes = gnomes.map{
var gnome = $0
gnome.age = 70
return gnome
}
Whilst the second keeps control over "ageing" private and simplifies mapping at the point of call:
struct Gnome {
private(set) var age: Int = 0
func aged(age: Int) -> Gnome {
var gnome = self
gnome.age = age
// any other ageing related changes
return gnome
}
}
gnomes = gnomes.map{ $0.aged(140) }
Of course, reference types still have their place in programming, which may well be a better fit in this case. The friction we are experiencing here suggests that we are trying to treat these structures as if they were objects. If that is the behaviour you need, then you should consider implementing Gnome as a class.

Having array problems in Swift

I am learning how to build apps and working with Swift for this project.
I had a buddy help me pull data in from a website and it looks like he created classes with variables and mapped them to certain extensions (IE "Username") so when I call the variable data such as profile I would call it. The below uses luck_30 able to store "Stats.luck_30"
luck_30.text = profile.luck_30
So inside one of my variables that is in this "Profile" class is setup into an array. I can pull the array out of the class, but I can't seem to do for while statement replacing the [#] with a variable from the for command.
func aliveWorkers(profile: Profile) -> NSNumber{
var myworkers : Array = profile.workers!
//this test works and returns the proper value
var testworker: NSNumber = myworkers[0].alive!
println("The satus of the test worker is " + testworker.description)
/* This code is giving error "Could not find member alive" it does not ifor var
for ifor in myworkers{
var thisworker: NSNumber = myworkers[ifor].alive! as NSNumber
}
*/
return 42
}
Your variable ifor is not a counter, it is an actual object. You could do something like this:
for worker in myWorkers {
let workerIsAlive = worker.alive!
}
Alternatively, if you need the index,
for i in 0 ..< myWorkers.count {
let worker = myWorkers[i]
let workerIsAlive = worker.alive!
}
If you need both:
for (i, worker) in enumerate(myWorkers) {
let workerIsAlive = worker.alive!
}
And as a matter of style, I would stay away from NSNumber and use Int or Bool or whatever the data actually is. Also, it looks like the alive variable should not be optional, as you're unwrapping it everywhere. To avoid "mysterious" crashes later, you may want to think about making it a non-optional type.
when using a for in loop, your loop variable isn't an index, its the objects you're looping through. so..
func aliveWorkers() {
var myworkers = [1, 2, 3]
//this test works and returns the proper value
let testworker = myworkers[0]
print("The satus of the test worker is \(testworker)")
for ifor in myworkers {
print(ifor)
}
}
Notice a few things... you don't need to use + to concatenate those strings. you can just use string interpolation. \(variable) inserts the value of variable in the string.
Try to use let instead of var when you don't change the variable. You don't need to explicitly define type on variables either.

Closures in loops capturing by reference?

Delegates in D seem to capture local values by reference, which has weird side effects when creating closures in loops: In the end, you have n closures with equal context pointers. Take this example:
import std.stdio;
alias Closure = void delegate();
Closure[] closures;
void main(){
foreach(a; ["Je", "Tu", "En", "Oui", "Na"])
closures ~= {write(a);};
foreach(c; closures)
c();
writeln(" batman");
}
This prints NaNaNaNaNa batman.
Is this expected behavior? If so, how would I work around it so it properly prints all array elements?
It gets even funnier when using a for-loop with counter variable, in the end i is equal to the array size, and when using closures[i] in the delegate it throws an out of bounds error.
Yes, that is expected behavior (EDIT: ...it is actually an oldstanding known bug! https://issues.dlang.org/show_bug.cgi?id=2043 so only expected in that it happens and you can easily get used to it, but it actually isn't supposed to happen) and is also seen in other languages, so this is a good principle to know.
To get a separate copy of the variables in the loop, call another function that returns the delegate you want to store, passing the loop variable to it.
import std.stdio;
alias Clojure = void delegate();
Clojure[] clojures;
void main(){
foreach(a; ["Je", "Tu", "En", "Oui", "Na"])
clojures ~= ((b) => { write(b);})(a);
foreach(c; clojures)
c();
writeln(" batman");
}
The clojures ~= ((b) => { write(b);})(a); line has changed: that defines a quick delegate that returns the delegate. The extra function-returning-function closes over a snapshot of the loop state, instead of just the function-level local variables.
I use this a lot in JavaScript too:
function makeHandler(item) {
return function() {
// use item here
};
}
var array = [1,2,3];
for(var I = 0; I < array.length; I++)
foo.addEventListener("click", makeHandler(array[I]));
This is the same thing done for the same reason as the D, just in different syntax, and broken up into bigger functions instead of trying to do it as a one-liner.
We define a function which returns a function that uses the captured loop variable. At the usage point, we call the one function which returns the delegate that is stored for later.
In the shorthand D syntax, ((b) => { write(b);})(a);, the (b) => ... is the makeHandler function seen in the javascript. The { write(b); } it returns is shorthand for return function() { ... } in JS (BTW that same JS syntax basically works ion D too, you can write a longhand thing with the delegate or function keywords. D's function doesn't capture variables though, delegate does that..)
Then, finally, the parenthesis around it and the (a) at the end is just to call the function. The stuff inside is the same as makeHandler, the (...)(a) calls it; it is makeHadndler(a).

What is the canonical way to convert an Array<Byte> to a ByteArray

If have an Array and want to convert it to a ByteArray, how should I go about it? The following for instance fails:
var srcArray = Array<Byte>(10, { 0 })
var tgtArray: ByteArray = srcArray as ByteArray
I do realize though that specialized classes such as ByteArray are:
... not related to the Array class and are compiled down to Java’s primitive arrays for maximum performance.
So, the fact that my approach fails shouldn't surprise me - but what is the canonical way to make the conversion? Simply iterate through srcArray and populate tgtArray one index at a time - or is there a more elegant solution I'm missing?
I don't see any built-in functions apart from the obvious loop-based approach. But you could define an extension function like this yourself:
fun Array<Byte>.toPrimitive(): ByteArray {
val tgtArray: ByteArray = ByteArray(this.size())
for (i in this.indices) {
tgtArray[i] = this[i]
}
return tgtArray
}
fun test() {
val srcArray = Array<Byte>(10, { 0 })
val tgtArray: ByteArray = srcArray.toPrimitive()
}
Kotlin has this in the stdlib as an extension function Array<Byte>.toByteArray()
val srcArray = Array<Byte>(10, { 0 })
val tgtArray = srcArray.toByteArray()
(Note: I changed your var to val which is more common in Kotlin to use read-only values)
You will see similar ones for other primitive data types that have array implementations. You can see them all in the Kotlin documentation for Array extension functions.

how can i put all the children of a movieClip into an Array?

I have an movieClip Container and I want to move all its children into an Array.
i think about the method I used to delete all children of a container by using while and removechild at 0, but I think it wont work in this situation. Anyone have a solution?
thanks for your help.
var parObj:DisplayObjectContainer = Container; /* Is that the name of your MC? */
var kids:Array = []
var kidCount:int = parObj.numChildren;
// please see note on push at bottom
for( var i:int = 0; i < kidCount; i++ ) kids.push( parObj.getChildAt( i ) );
TA-DA! kids is now an array of all children of parObj
as a function:
function getChildren( parObj:DisplayObjectContainer ):Array
{
var kids:Array = []
var kidCount:int = parObj.numChildren;
for( var i:int = 0; i < kidCount; i++ )
kids.push( parObj.getChildAt( i ) );
return kids
}
Or, if you're courageous enough for vectors (the result of this function can only hold DisplayObjects and it is slightly faster than a normal array):
function getChildren( parObj:DisplayObjectContainer ):Vector.<DisplayObject>
{
var Vector.<DisplayObject> = new Vector.<DisplayObject>();
var kidCount:int = parObj.numChildren;
for( var i:int = 0; i < kidCount; i++ )
kids.push( parObj.getChildAt( i ) );
return kids
}
EDIT
It was pointed out that this loop was not optimizing numChildren. I will agree (within reason -- chances are this will not be a bottleneck), so it is now an int. A good point to that SOer.
But, there have been two comments made vis-a-vis push vs. kids[ kids.length ] = parObj.getChildAt( i );
When it comes to assigning array indexes, my experience is that situations where push vs. arr[ i ] = val truly make that much of a difference, it is likely that something else is going on which should be optimized first -- are you really getting an array of the children of a MovieClip hundreds (thousands?) of times? Then maybe you don't really need an array of DisplayObject, maybe you need to remove the extra loop and handle all of this (more or less) inline. Do you really have a thousand length array? Then your bottleneck is probably going to be related to the fact that you're dealing with a large, unwieldy data structure and not the loop in itself.
I find push to be clear, explicit, and most important, obvious. arr.push takes no time to understand, it is a self-contained statement, whereas array index assignment requires me, at least, to actually look. Further, because push is a method call and arr.length is a property of a dynamic object, push also defends against the possibility of typos: arr[ arr.lengt ] causes no errors! It is valid code! arr.pus(value), on the other hand, causes a TypeError. Don't know about the rest of the world, but I don't have time to deal with obscured typos.
Assigning array indexes directly, to me, is premature optimization. If you feel otherwise, that's fine (and by all means, vote me down, that is the point of the site -- hopefully we'll all agree on an acceptable practice), but push will be my standard.
You can use a combination of numChildren and getChildAt() to loop through your elements within a container. The following code assumes that you're running the code from within the container. If this isn't the case, just prefix those two properties with the name of your container:
var ar:Array = [];
var i:int = 0;
for(i; i<numChildren; i++)
{
var mc:DisplayObject = getChildAt(i);
ar[ar.length] = mc;
}
trace(ar.length);

Resources