AS3, (phrase + Integer variable) for Boolean check? - actionscript-3

I have a number of functions and variables depending on a particular Integer variable, "i". Is it possible to write a Boolean variable itself as the base phrase plus the integer variable?
For example, something like:
["boolCHECK" + i] = true;
Instead of:
if (i == 1)
{
boolCHECK1 = true;
}
if (i == 2)
{
boolCHECK2 = true;
}
... etc.

Your code should work. You may get a compiler error though since you're not referencing a known object. To remedy that, just reference this:
this["boolCHECK" + i] = true;
That said, you should probably just use an array for this scenario as it's cleaner and less prone to typo's. As pointed out in the comments by #fsbmain, this is a good candidate for a vector:
var checks:Vector.<Boolean> = new <Boolean>[true, false, true, false]; //etc
//later
checks[i] = true;

Related

Searching array for letters case insensitive in AS3

I am an absolute newbie to ActionScript 3 and I need to create a function that searches an array of alphabets for a specific letter and return its index. I already found the indexOf which is perfect. But I need this search to be not case sensitive. Like if my array is this:
Array("a","B","c")
if I am looking for "A" the index returned would be 0.
Is there some predefined function for this?
I don't think there is a predefined function for this.
You can write your own, though. Use a for-loop and iterate through the array, using String.toLowerCase() to alter both the array value and the check value temporarily for checking.
Actually... asking you to write your own is asking you to shoot yourself in the foot for something like this. Create a class ArrayUtils, stuff this function in it.
/**
* Searches through an array for a case-insensitive string match.
* Attempts to imitate Array.indexOf where it can.
* #param arr The array to search through
* #param searchingFor The string to search for
* #param fromIndex Optional, an index to start searching at.
* #returns The index of the array that a match was found at (zero-indexed), or -1 if no match was found.
*/
public static function indexOfCaseInsensitiveString(arr:Array, searchingFor:String, fromIndex:uint = 0):int {
var lowercaseSearchString:String = searchingFor.toLowerCase();
var arrayLength:uint = arr.length;//Retrieving array length is expensive, optimization
for(var index:uint = fromIndex; index < arrayLength; index++){
var element:* = arr[index];
if(element is String && element.toLowerCase() == lowercaseSearchString){
return index;
}
}
return -1;//It wasn't found in the array.
}
You could then call it via ArrayUtils.indexOfCaseInsensitiveString(<your array>, <your string>). The fromIndex is just there to mimic the regular indexOf (principle of least surprise; if I say it's "indexOf with case-insensitive string search", why would that affect fromIndex?).
Regular Expressions may be used to achieve this using the case insensitive flag.
function findTargetIndex(needle:String,heystack:Array):int
{
var straw:String;
var magnet:RegExp = new RegExp(needle,"i");//"i" flag makes the search case insensitive.
//can also be done with magnet.ignoreCase = true;
for (var x:int = 0; x < heystack.length; x++)
{
straw = heystack[x];
if (straw.search(magnet) > -1) return x;
}
return -1;
}
The above function would search the array looking for any element that contains your search string. You can limit it to matching whole strings only by altering the RegExp;
var magnet:RegExp = new RegExp("^"+needle+"$","i");
^ matches the beginning of a string, $ matches the end, meaning the whole string must match the whole expression.
disclaimer: I havn't compiled this code, this is just to demonstrate how I would go about it.
you should check nulls and non-string variables. you should use Vector.<String> instead of Array
nope, there is none.
the simplest way:
function getCaseInsensitiveIndexOf(needle:String, haystack:Array):int
{
var index:int = -1;
if(needle != null)
{
index = haystack.indexOf(needle.toUpperCase());
if(index == -1)
index = haystack.indexOf(needle.toLowerCase());
}
return index;
}
// bellow is my first answer, but its overkill
you have to normalize the content of the array beforehand.
you possibly want to normalize a copy of it actually, so you don't loose any detail.
function getNormalizedVersionOf(target:Array):Array
{
var copy:Array = [];
for(var i:int = 0; i < target.length; i++)
{
copy[i] = (target[i] as String).toUpperCase(); // or .toLowerCase()
}
return copy;
}
and when you search, you search on the normalized copy
function getItemIndex(searchFor:String):int
{
var s:String = searchFor.toUpperCase();
return mNormalized.indexOf(s); //if you have the copy array as a class member called mNormalized
}

as3 reuse datagrid cellrenderer with different variables

I have a couple very large datagrids with custom cell renderers. The issue I am facing is that I now have > 80 of these, 1 for each column per data grid.
I'm curious if there is a way I can get these reduced down into 1 global cell renderer that I could pass variables into to define what is allowed by the cell renderer for that column.
ie:
...
col1 = new DataGridColumn("PurchaseStartDate");
col1.headerText = "Purchase Date (YYYY-MM)";
dg.addColumn(col1);
col1.width = 110;
col1.editable = false;
col1.sortable = false;
col1.cellRenderer = Alternating_Row_Colours_editable36;
Alternating_Row_Colours_editable36._dg = dg;
Alternating_Row_Colours_editable36.__enabled = true;
Alternating_Row_Colours_editable36._myCol = 12;
Alternating_Row_Colours_editable36._isNum = 3;
Alternating_Row_Colours_editable36._stage = this;
Alternating_Row_Colours_editable36._maxChars = 9;
within the cell renderer I'm using all of those variables to customize what is allowed.
ie:
...
public function Alternating_Row_Colours_editable36()
{
super();
if(_isNum == 0){
restrict = "a-z A-Z #_,.0-9//-";
maxChars = 64;
}else if (_isNum == 1){
restrict = ".0-9";
maxChars = 9;
}else if (_isNum == 2){
restrict = "0-9";
maxChars = 2;
}else if (_isNum == 3){
restrict = "0-9 \\-";
maxChars = 9;
}else if (_isNum == 4){
restrict = "0-9. %";
maxChars = 9;
}
if(_maxChars != -1){
maxChars = _maxChars;
}
The issue if you look at the above, I just noted that I had an error. I used "//-" to escape the hyphen instead of "\-". Now I've got 80+ changes to make and every time I try to add something new, for a callback, restricts, max chars, making it editable, scrubbing the input, changing it from dynamic to input and back again...
I would love to know if there is a way, to create an instance of the class and use that cell renderer. Or to be able to pass variables that affect only that column and not all columns.
I'm not the best, but I was under the impression that it might just be a set/get function I need to use, or change the variables to protected, private or something to get this desired result.
Anyone have any suggestions on how to bring these 80+ cell renderers under control. As I am not looking forward to needing to make the changes to them for sorting down the road...
jc
I know this is a very late reply and you've more than likely moved on by now!
You can do it by using the information in 'listData' property of the CellRenderer class:
// Create a private class level variable called _dataField...
private var _dataField:String;
// Assign the dataField...
public function set listData(value:ListData):void {
_listData = value;
this._dataField = DataGridColumn(DataGrid(this._listData.owner).columns[this._listData.column]).dataField;
// set the data again now...
this.data = _data;
invalidate(InvalidationType.DATA);
invalidate(InvalidationType.STATE);
}
// Use the dataField when setting value from DataProvider...
public function set data(value:Object):void {
_data = value;
if (this._dataField != "")
{
this.text = value[this._dataField];
}
}
Hope that satisfies any curiosity. Shame they don't just pass that property to the CellRenderer in the first place!
Cheers

How to change my code to target a list of display objects?

if( listnumber != "listBox1")
this[listnumber].visible = false;
else
this[listnumber].visible = true;
I would like to change this statement to make the new listnumber visible, and make any other invisible.
Thanks to Baris Usakli for suggesting the mentioned code, my question just needed to be clearer
function makeVisible(a:Array,s:String):void{
for (var i:int = 0; i < a.length; i++)
{
if(a[i].name == s)
a[i].visible = true;
else
a[i].visible = false;
}
}
Your question is confusing so I've done the best I can to decipher what you want done. You can call that function from your script passing the array of objects and the string you want tested based on a variable (change the variable "name" to whichever is required) through the parameter. This won't work if there are objects with the same name (or at least it'll turn all objects with that name visible and all others invisible).
Hope it helps.

How can I check if an array contains another array?

At first sight it's very simple, but I'm having some problems to do this without using a lot of nested loops.
Example:
var father:Array = new Array(0,1,2,3,4,5);
var son:Array = new Array(3,4,5);
father.contains(son) // returns true or 4(the starting index if the contained array)
ActionScript 3 actually supports some slightly crazy stuff, due to the fact that, in the early days, Adobe/Macromedia were trying to make it compliant with Ecmascript.
So... you can do this:
var a1:Array = [1,2,3,4,5,6,7,8,9];
var a2:Array = [3,4,5];
// borrow String's indexOf function, and it magically works on Arrays
// but rename it because Array already has a different indexOf function
a1.indexOf2 = String.prototype.indexOf;
trace(a1.indexOf2(a2) > -1); // true
But you need to be a little bit careful because it will convert all the elements to Strings for the equality test. For primitives, it mostly won't matter but it will break badly with objects as they'll all be converted to "[object Object]" or to whatever their toString() returns.
Also, if you wanted to use the actual index for anything, rather than just checking it's not -1, you have to divide by two, as the number is double what you'd expect. I don't exactly know why this is :)
If you need something more general and reliable, you'd be better off writing a function to do an explicit search. This is a quick example, which I just wrote so could easily be bug-ridden:
public function find(haystack:Array, needle:Array):int
{
var index:int = -1;
while(index <= haystack.length - needle.length)
{
index++;
index = haystack.indexOf(needle[0], index);
for( var i:int = 1; i<needle.length; i++)
{
if(haystack[index+i] != needle[i])
{
continue;
}
}
if( i == needle.length)
{
return index;
}
}
return -1;
}
Try this for simplicity:
// Determines if an array contains en element (similar to the PHP function with the same name)
public function in_array(needle:*, haystack:Array):Boolean
{
for each (var element:* in haystack)
{
if (element == needle) {return true;}
}
return false;
}

ActionScript Comparing Arrays

how can i evaluate whether my test array is equal to my static constant DEFAULT_ARRAY? shouldn't my output be returning true?
public class myClass extends Sprite
{
private static const DEFAULT_ARRAY:Array = new Array(1, 2, 3);
public function myClass()
{
var test:Array = new Array(1, 2, 3);
trace (test == DEFAULT_ARRAY);
}
//traces false
Macke has already pointed out the problem. The == operator will tell you (for reference types such as Array objects) if two variables point to the same object. That's clearly not the case here. You have 2 different objects, that happen to have the same content.
So, what you're probably looking for is a way to compare whether 2 arrays have the same contents. This apparently simple task might be trickier than it seems.
The standard way is using a function like this:
function areEqual(a:Array,b:Array):Boolean {
if(a.length != b.length) {
return false;
}
var len:int = a.length;
for(var i:int = 0; i < len; i++) {
if(a[i] !== b[i]) {
return false;
}
}
return true;
}
This will work in some (arguably most) cases. But it will fail if the items in any of the arrays have reference type semantics (as opposed to value type semantics). Basically, Numbers (including ints and uints), Strings, Boolean, null and undefined have value type semantics:
Given:
var a:int = 0;
var b:int = 0;
This will hold true:
trace(a == b);
For everything else, comparing with == will only return true if both vars reference the same object:
var a:Object = {data:1};
var b:Object = {data:1};
trace(a == b); // false
But
var a:Object = {data:1};
var b:Object = a;
trace(a == b); // true
So, if your arrays contain objects (or in turn other Arrays), the areEqual will fail in this case:
var arr_1:Array = [{data:1}];
var arr_2:Array = [{data:1}];
trace(areEqual(arr_1,arr_2));
Why? Because the {data:1} object that you stored in arr_1 is different from the {data:1} object stored in arr_2.
I don't think it's possible to create a generic function that checks recursively whether two arrays' contents are equal, because there's no generic way of determinig whether two objects should be considered equal. This really depends on your objects, your domain, etc. I.e. in your app, two objects should be considered equal if they have the same ìd (assuming you have defined an ìd property). As I think this shows, there's no way to know before hand what makes to objects equal.
Dude, use the mx.utils.ObjectUtil... the creators of actionscript have already thought about this.
ObjectUtil.compare(this.instructions, other.instructions) == 0;
What you're doing there is comparing references, not values. This is because an array is not a value type. A number is a value type, for instance. A number with the value of 3 will always be equal to 3, no matter what references you compare. But a reference type, a block of memory accessed by reference, is just that, a block of memory. If you've got two references to the same block, they'll be considered equal. But again, you're really just comparing the references and not the actual values.
In your case, your conditional would be true if you had the following code:
private static const DEFAULT_ARRAY:Array = new Array(1, 2, 3);
public function myClass()
{
var test:Array = DEFAULT_ARRAY;
trace (test == DEFAULT_ARRAY);
}
//traces true
Which rather makes sense, since test is now referencing the same memory as is referenced by the constant. In order to make sure the arrays contain the same values, you need to loop through the array and compare the items:
private static const DEFAULT_ARRAY:Array = new Array(1, 2, 3);
public function myClass()
{
var test:Array = new Array(1, 2, 3);
var isEqual:Boolean = true;
for (var i:int = 0; i < test.length; i++)
{
if (test[i] == DEFAULT_ARRAY[i])
continue;
else
{
isEqual = false;
break;
}
}
trace (isEqual);
}
//traces true
Hamcrest could be useful in these types of scenarios.