Easiest way to order array from a string word - Interesting - arrays

I am writing a childrens game and it consists of letter blocks.
The child has to put the blocks in a correct order (following silhouettes) to spell the word
Now my question is I have 2 Arrays.
var myLetters = new Array(
new BlockC(),
new BlockA(),
new BlockB()
);
public static var myLetters2 = new Array(
new BlockC(),
new BlockA(),
new BlockB()
);
So you see this is setup to spell the word C A B.
What i would would like to do is have a string variable that i can put the word in to and then have code fill the array in the correct order.
i.e.
var word:String = "CAB";
Hope this makes sense and i can get some good help from you guys
Thanks

If I understand the question correctly, here is one way of doing it :
var word:String = "CAB";
var letterClassMapping:Object = {
"C":BlockC,
"A":BlockA,
"B":BlockB
};
var myLetters:Array = [];
for(var i:int=0; i<word.length; i++) {
myLetters.push( new letterClassMapping[word.charAt(i)]() );
}
Another way is to use getDefinitionByName to get the class type :
var classType:Class = getDefinitionByName("Block" + word.charAt(i)) as Class;
myLetters.push(new classType());

You seem to need a letter collection with corresponding classes. So, you make yourself an Object of the following srtructure:
private static var LETTERS:Object={A:BlockA,B:BlockB,C:BlockC};
Then you split your word by single letters (copy one letter out of a word into a new string) and then you can get corresponding class via LETTERS[letter], and a new instance of that class via new LETTERS[letter]();

You can also create toString() functions in Your object and thant join array .
In class create function :
public class BlockA {
public function toString():String {
return "A";
}
}
And than You can join array items :
var arr:Array = [new BlockA , new BlockB , new BlockC];
trace(arr.join(""));
// and compare to Your string:
arr.join("") == word;

Related

Create an array of Struct arrays?

I have a query that builds a Struct array from some objects. I want to append multiple of these structs into a single array so that i can use it populate a collectionview that is nested inside a collectionview. Im not sure this is the best idea but its all I've got a the moment.
So my Struct is:
struct CollectionStruct {
var name : String
var description : String
var title : String
var image : PFFile
var id: String
}
In my viewcontroller the variable to hold the struct is thus:
var packArray : [CollectionStruct] = []
var partArray : [CollectionStruct] = []
var packId = ""
So below what I'm doing is using an item of the previously created packArray to query the DB and build my partArray. Because i want to do this multiple times and append the partArray into a larger parent array i was thinking of using a for loop like:
var i = 0
for item in self.packArray as [AnyObject] {
self.packId = self.packArray[i].id
BuildArray.buildArrayFromQuery(queryForCollection: "Part", selectedPackID: self.packId, delegateSender: "DownloadPart", completeBlock: { (result) in
self.partArray = result
// append this to an array of partArray????
})
}
I don't even know where to start with this. Is it a bad idea?
essentially what i thought was to call this parent array in cellforitem maybe something like:
innerCell.imageCell.image = parentArray[indexPath.item].partArray[indexPath.item].image
but i could be way off.
----- EDIT -----
so i can use a multidimensional array inside the closure once self.partArray is set:
self.partArray = result
var parentArray = [[self.partArray]]
parentArray.append([self.partArray])
but this is unusable outside the closure. How to declare this multidimensional array before self.partArray is set?
------- EDIT -------
Looking into globals for this at the moment.
class GlobalPartArray {
private init() { }
static let sharedInstance = GlobalPartArray()
var globalPartArray = [CollectionStruct]()
}
class GlobalParentArray {
private init() { }
static let sharedInstance = GlobalParentArray()
var globalParentArray = [[GlobalPartArray]]()
}
then inside closure:
GlobalPartArray.sharedInstance.globalPartArray = result
//can not convert [CollectionStruct] to [GlobalPartArray]
GlobalParentArray.sharedInstance.globalParentArray.append(GlobalPartArray.sharedInstance.globalPartArray)
but it throws an error when trying to convert. I obviously need to convert this data somehow before appending to the GlobalParentArray.

Sort an Array, populated by an IsolatedStorageFile text file seems to move the 0 entry

I have the code below that splits a text file from IsolatedStorage, populates an Array with the data, sorts it, and then assigns it as the source for a ListPicker:
var splitFile = fileData.Split(';');
string[] testArray = splitFile;
Array.Sort<string>(testArray);
testLocationPicker.ItemsSource = testArray;
However, it doesn't seem to populating the array correctly and the sorting doesn't appear to be working as expected either.
The testArray[0] is blank, when it should be populated. When the output is shown the entry that should be at [0] appears at the bottom.
BEFORE SORTING:
AFTER SORTING:
It's only in sorting the array that it seems to screw up the order.
UPDATE: I tried the suggested:
var splitFile = fileData.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
string[] testArray = splitFile;
Array.Sort<string>(testArray);
testLocationPicker.ItemsSource = testArray;
This still results in the second screenshot, above.
When the app first ever runs I do this:
StringBuilder sb = new StringBuilder(); // Use a StringBuilder to construct output.
var store = IsolatedStorageFile.GetUserStoreForApplication(); // Create a store
store.CreateDirectory("testLocations"); // Create a directory
IsolatedStorageFileStream rootFile = store.CreateFile("locations.txt"); // Create a file in the root.
rootFile.Close(); // Close File
string[] filesInTheRoot = store.GetFileNames(); // Store all files names in an array
Debug.WriteLine(filesInTheRoot[0]); // Show first file name retrieved (only one stored at the moment)
string filePath = "locations.txt";
if (store.FileExists(filePath)) {
Debug.WriteLine("Files Exists");
StreamWriter sw =
new StreamWriter(store.OpenFile(filePath,
FileMode.Open, FileAccess.Write));
Debug.WriteLine("Writing...");
sw.WriteLine("Chicago, IL;");
sw.WriteLine("Chicago, IL (Q);");
sw.WriteLine("Dulles, VA;");
sw.WriteLine("Dulles, VA (Q);");
sw.WriteLine("London, UK;");
sw.WriteLine("London, UK (Q);");
sw.WriteLine("San Jose, CA;");
sw.WriteLine("San Jose, CA (Q);");
sw.Close();
Debug.WriteLine("Writing complete");
}
Then when I add to the file I do this:
StringBuilder sb = new StringBuilder(); // Use a StringBuilder to construct output.
var store = IsolatedStorageFile.GetUserStoreForApplication(); // Create a store
string[] filesInTheRoot = store.GetFileNames(); // Store all files names in an array
Debug.WriteLine(filesInTheRoot[0]); // Show first file name retrieved (only one stored at the moment)
byte[] data = Encoding.UTF8.GetBytes(locationName + ";");
string filePath = "locations.txt";
if (store.FileExists(filePath))
{
using (var stream = new IsolatedStorageFileStream(filePath, FileMode.Append, store))
{
Debug.WriteLine("Writing...");
stream.Write(data, 0, data.Length); // Semi Colon required for location separation in text file
stream.Close();
Debug.WriteLine(locationName + "; added");
Debug.WriteLine("Writing complete");
}
}
I'm splitting using a ";" could this be an issue?
There's no problem with the sort: 'space' is considered to come before 'a', so it appears on top of the list. The real problem is: why do you have an empty entry to begin with?
My guess is that, when creating the file, you're separating every entry with ;, including the last one. Therefore, when parsing the data with the string.Split method, you're left with an empty entry at the end of your array.
An easy way to prevent that is to use an overload of the string.Split method that filters empty entries:
var splitFile = fileData.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
I went a different way using IsolatedStorageSetting and storing Arrays/Lists to do what I wanted.

How can I make an object's key more dynamic?

I have an AssetManager singleton that I'm using as a data provider of sorts.
public static var L1_1:Object = {pic:'../Assets/images/test.jpg', answer:'someAnswer', pool: 'somePool'}
So I'm trying to use this in another class to get a path for an image class that takes a string as a param like so:
var image:Image = new Image(AssetManager.L1_1.pic , 540, 540);
This works great, however, I need to increment the second '1' above to make it dynamic so I can say for eg.,
var image:Image = new Image(AssetManager.L1_5.pic , 540, 540);
I have tried things like this, passing an imageNum property but can't sort it.
var tempObj:Object = ['AssetManager.L' + imageNum + '_' + imageNum + '.pic'];
trace(tempObj)
Is there an easier way to do this? Thanks!!
Static and public properties in AS3 can be accessed using bracket syntax.
Here's an example:
public static var L1_1:Object = {pic:'../Assets/images/test.jpg', answer:'someAnswer', pool: 'somePool'};
var imageNum:int = 1;
var propertyName:String = "L1"+ "_" + imageNum.toString();
var tempObj:Object = AssetManager[propertyName];
var pathToPic:String = tempObj.pic;
trace(pathToPic);
The above example should trace out ../Assets/images/test.jpg
However, be aware that bracket syntax is slower than dot syntax and is not type checked at compile time.
I hope this helps.
I have a fix for now by simply using an array like so:
public static var L1_1:Array = new Array();
L1_1[0] = ['../Assets/images/test.jpg', "apple", "appletakeout"];
And calling it with:
image = new Image(AssetManager.L1_1[0][imageNum], 540, 540);
And it works, just feels a tiny bit messy. If there's a more efficient way to do this I'd love to hear. Thanks.

using a variable name to load movie clip to stage using As3

I have created a Spelling Puzzle in AS3 that loads a list of words from an XML file into an Array.
As the code loops through the array, it assigns each word to a variable called "current_word", then scrambles the letters of "current_word" and displays them on stage.
I would like to add an animated MovieClip as a visual aid with the class name that matches the value of current word.
For example if the current word is 'bear', then a MovieClip with the class name 'bear' is loaded from library to stage.
I was trying to create an empty movie clip called "tempItemClip" and overwrite its value with the value of the var current_word.
No errors, but it's not working. I am new to ActionScript. Can someone advise me on the best solution?
public function getWord()
{
current_word=pWord[ques_num];
setTiles(current_word.length);
ques_num++;
trace(current_word);
var tempItemClip:MovieClip = new MyItem();
Puzzle_screen.addChildAt(tempItemClip,4);
tempItemClip.x=380;
tempItemClip.y=130;
//var myClip:Object = getDefinitionByName(current_word);
var myClip:MovieClip = new MovieClip();
tempItemClip[current_word] = myClip;
tempItemClip.addChild(myClip);
}
It's not clear what you are asking, but I believe this is what you want :
var clipClass:Class = getDefinitionByName(current_word) as Class;
var myClip:MovieClip = new clipClass();

Efficient way to filter an Object Array on a specific property?

I have an array of objects with different properties and I need to filter the array in a way that a specific property is not duplicated.
For example:
var array:Array = [{foo:"a1", bar:"b1", baz:"c1"},
{foo:"a2", bar:"b2", baz:"c2"},
{foo:"a3", bar:"b1", baz:"c3"},
{foo:"a1", bar:"b4", baz:"c2"},
{foo:"a0", bar:"b3", baz:"c1"}];
Now suppose I want to filter the objects on the property baz. What is the most efficient way of filtering the array, so that no two elements have the same value for baz after the operation?
In my example, the result should only contain:
var result:Array = [{foo:"a1", bar:"b1", baz:"c1"},
{foo:"a2", bar:"b2", baz:"c2"},
{foo:"a3", bar:"b1", baz:"c3"}]
since the other objects would have duplicate entries for the baz property.
The order of the result array is not important, neither is which object of those with identical values for baz makes it into the result array.
Update:
The object array is used as a dataprovider to populate a s:Datagrid with information about chatrooms. The objects in the array carry related information (like the room's ID on the server and some other config settings).
The baz property I used in my example is actually the ID of the language the chat room is configured to use and I want to create a s:DropDownList with which I can filter the Datagrid for individual languages (e.g. show all rooms that use "German").
It is very likely to have many objects with the same language ID, but I only want each language Id to show up once in the DropDownList.
I need to extract that information from the Datagrids's dataprovider (the source array) and cannot retrieve my languages directly since the DropDownList is part of a generic DatagridHeaderRenderer that is used in many different Datagrids with different data.
private var array:Array = [{foo:"a1", bar:"b1", baz:"c1"},
{foo:"a2", bar:"b2", baz:"c2"},
{foo:"a3", bar:"b1", baz:"c3"},
{foo:"a1", bar:"b4", baz:"c2"},
{foo:"a0", bar:"b3", baz:"c1"}];
private var filteredArray:Array;
private var keys:Object = {};
private function filterArray():void{
filteredArray = arr.filter(removeDupes);
}
private function removeDupes(item:Object, idx:uint, arr:Array):Boolean {
if (keys.hasOwnProperty(item.baz)){
return false;
} else {
keys[item.baz] = item;
return true;
}
}
private function resetFilter():void{
filteredArray = new Array();
keys = {};
}
Modified from multiple sources but primarily: http://blog.flexexamples.com/2007/08/05/removing-duplicate-items-from-an-array-using-the-arrayfilter-method/
Or you could just use an arrayCollection and its built-in filterFunction. See: http://cookbooks.adobe.com/post_Using_the_to_ArrayCollection_s_filterFunction-5441.html
On the surface of it looks like it should work. Using Array.filter is usually about twice the time of doing the same thing in a loop.
I'd argue that' Dom's removeDupes function doesn't do exactly what's required, although it might be a more generic approach (if, for example, the === isn't a good comparison function, then this gives you a way of extending it.) But using hasOwnPropery is a big no-no. You should never touch it - that function only exists for ES compatibility. It is evil otherwise - both a potential security hole (as it is defined on Object.prototype and thus is easy to override for the foreign code) and is slow (for the same reason - the lookup of the functions defined on prototype is slower then those defined in a class).
public function Test()
{
super();
var array:Array = [{foo:"a1", bar:"b1", baz:"c1"},
{foo:"a2", bar:"b2", baz:"c2"},
{foo:"a3", bar:"b1", baz:"c3"},
{foo:"a1", bar:"b4", baz:"c2"},
{foo:"a0", bar:"b3", baz:"c1"}];
this.removeDuplicates(array, "baz").map(this.objectTracer);
// { foo : a3, baz : c3, bar : b1 }
// { foo : a1, baz : c2, bar : b4 }
// { foo : a0, baz : c1, bar : b3 }
}
private function objectTracer(object:Object, index:int, all:Array):void
{
var result:String = "";
for (var p:String in object)
result += ", " + p + " : " + object[p];
if (result) result = result.substr(2);
trace("{ " + result + " }");
}
private function removeDuplicates(array:Array, on:String):Array
{
var result:Array = array.concat();
// note that since we use `Dictionary' the
// the comparison between objects is the same as `==='
// if all values are strings, you can use `Object' to
// save some space.
var hash:Dictionary = new Dictionary();
var temp:Object;
for (var i:int, j:int = result.length - 1; j >= i; j--)
{
temp = result[j][on];
if (temp in hash)
{
result[j] = result[i];
j++; i++;
}
else hash[temp] = true;
}
// note that we could `shift()` until we get to `i'
// but when we do it, we actually reallocate the array every time
// so `slice()' must, in theory, be more efficient
return result.slice(i);
}

Resources