How to check if jsonjavaobject is already part of an array? - arrays

I am building a simple array of jsonobjects via:
var jsonObjArr = sessionScope.get("tmpAssessors");
var jsonObj:com.ibm.commons.util.io.json.JsonJavaObject = new com.ibm.commons.util.io.json.JsonJavaObject();
var area = getComponent("inpArea").value;
var person = getComponent("personField").value;
jsonObj.putJsonProperty("area", area);
jsonObj.putJsonProperty("person", person);
jsonObjArr.push(jsonObj);
sessionScope.put("tmpAssessors",jsonObjArr);
However I would like to check if a similar jsonobject (same key-pair values) is already in the array so I will not push it in a second time.
How can I check this?

Provided that JsonJavaObject.equals performs a correct equality check, your code should work if you replace jsonObjArr.push(jsonObj); with the following:
var _doesArrayContainElement=function(a,e){
var i;
for (i=0;i<a.length;i++) {
if (a[i].equals(e)) return true;
}
return false;
}
if (!_doesArrayContainElement(jsonObjArr,jsonObj)) jsonObjArr.push(jsonObj);

Related

Looping for events in actionscript 3, only get last number

So I want to code faster by making array of all button that I have, and also make array of function which index numbers are connected to the array of each buttons.
For example, buttons[0], handler events for hover is button_over_funcs[0] and for out is button_out_funcs[0].
To make it clearer (since english is not my first language), take a look at my code:
var buttons:Array = [playbtn, tutorialbtn];
var button_over_funcs:Array = new Array();
var button_out_funcs:Array = new Array();
var i = 0;
for each(var j in buttons){
j.buttonMode = true;
button_over_funcs.push(function(e:MouseEvent){
j.gotoAndPlay("hover");
});
button_out_funcs.push(function(e:MouseEvent){
j.gotoAndPlay("out");
});
j.addEventListener(MouseEvent.ROLL_OVER, button_over_funcs[i]);
j.addEventListener(MouseEvent.ROLL_OUT, button_out_funcs[i]);
i++;
}
but the j will always refer to tutorialbtn, regardless which button I hover/out. I tried for-in as well
var buttons:Array = [playbtn, tutorialbtn];
var button_over_funcs:Array = new Array();
var button_out_funcs:Array = new Array();
for(var j in buttons){
buttons[j].buttonMode = true;
button_over_funcs.push(function(e:MouseEvent){
buttons[j].gotoAndPlay("hover");
});
button_out_funcs.push(function(e:MouseEvent){
buttons[j].gotoAndPlay("out");
});
buttons[j].addEventListener(MouseEvent.ROLL_OVER, button_over_funcs[j]);
buttons[j].addEventListener(MouseEvent.ROLL_OUT, button_out_funcs[j]);
}
Both seems the same. It seems like actionscript always refers to the last value of j instead of assigning it. Do you have any idea on how to make this as I expected? Is it impossible to make this quicker and not assigning the button to do same exact stuff?
There's no point in reinventing the wheel. Use SimpleButton and be done with it.
In general: a class is the way to go when you want to define behaviour that several objects have in common.
So I found the way by myself. If you found same problem as me, you can take a look.
var buttons:Array = [playbtn, tutorialbtn];
var button_over_funcs:Array = new Array();
var button_out_funcs:Array = new Array();
function addOver(ob){
button_over_funcs.push(function(e:MouseEvent){
ob.gotoAndPlay("hover");
});
}
function addOut(ob){
button_out_funcs.push(function(e:MouseEvent){
ob.gotoAndPlay("out");
});
}
function addEvent(ob){
addOver(ob);
addOut(ob);
}
for each(var j in buttons){
addEvent(j)
}
for(var i = 0; i<= buttons.length - 1; i++){
buttons[i].buttonMode = true;
buttons[i].addEventListener(MouseEvent.ROLL_OVER, button_over_funcs[i]);
buttons[i].addEventListener(MouseEvent.ROLL_OUT, button_out_funcs[i]);
}

Select random elements from an array without repeats?

edit: I can't believe I didn't catch this sooner. Turns out my problem was re-declaring my first variables over and over again, essentially starting the program fresh instead of continuing it. To fix it, I replaced the first two lines with this:
if (initialized === undefined) {
trace("INITIALIZING");
var MCs = [];
var lastPos = "intializer";
var initialized = 1;
}
Now it works like a charm. I feel like a noob for this one; sorry to anyone whose time I wasted. I'd post this as an answer to my own question, but it won't let me since I'm still new.
Original Post follows:
I'm trying to make a flash that will randomly choose an ad, play it, and then randomly play another. To that end, I've succeeded by shuffling an array, and then gotoAndPlay-ing the label in the first element of the array, and then removing that element. At the end of each ad is gotoAndPlay(1); with all the main code being on the first frame. If the array is empty, it rebuilds it and reshuffles it.
The problem is, I don't want it to repeat any ads until its run through all of them; I think I've got that down, but I'm not positive. Further, I don't want the last element in the array to be the same as the first in the new one, so the same ad won't ever show twice in a row. I'm trying to have it detect if the element it just used matches the one it's about to use, and reshuffle if that happens, but in my testing it continues to occasionally show the same ad twice in a row.
I'm obviously doing something wrong, but being entirely new to ActionScript3 (and in fact to flash) I'm having a lot of trouble identifying what it is. Here's what I have right now:
var MCs = [];
var lastPos = "intializer";
if (MCs.length == 0) {
MCs = reset();
if (lastPos == MCs[0]) {
while (lastPos == MCs[0]) {
MCs = reset();
}
}
}
if (MCs.length > 0) {
lastPos = MCs[0];
MCs.splice(0,1);
gotoAndPlay(lastPos+"MC");
}
function reset(){
var PrepMCs = new Array("Image1", "Image2", "Image3");
var WorkMCs = new Array(PrepMCs.length);
var randomPos:Number = 0;
for (var i:int = 0; i < WorkMCs.length; i++)
{
randomPos = int(Math.random() * PrepMCs.length);
WorkMCs[i] = PrepMCs.splice(randomPos, 1)[0];
}
return WorkMCs;
}
Personally, I'd rather just do this with JavaScript, HTML, and images; it'd be really simple. But for hosting/CMS reasons I don't have any control over, I'm limited to a single file or a single block of code; I can't host anything externally, which as far as I can tell leaves Flash as my best option for this.
Any help would be greatly appreciated, thanks! If I've done something horribly, horribly wrong, and it's a wonder this even runs at all, don't hesitate to tell me!
edit: It just occurred to me, it is perfectly fine if the second run is in the same order as the first run, etc. The main thing is, it needs to be random. This is probably much easier to implement.
edit 2: MASSIVE DERP HERE. Every time it runs, it re-initializes MCs and lastPos... in other words, it's shuffling every time and starting over. What I should be researching is how to only run a line of code if a variable hasn't been initialized yet.
Blatantly stealing from #32bitKid, this is my version.
The main problem I have with his solution is the push/splice idea. As much as possible, I like to create once, and reuse. Shrinking and growing arrays is bulky, even if effective.
Also, this method does not re-order the array, which may or may not be valuable.
BTW, I like the way that he prevents a repeat of the previous item ("almost empty").
So here is another method:
package
{
public class RandomizedList
{
private var _items:Array;
private var idxs:Array;
private var rnd:int;
private var priorItemIdx:int;
private var curIdx:int;
public function RandomizedList(inarr:Array)
{
items = inarr;
}
private function initRandomize():void
{
idxs = new Array();
//Fisher-Yates initialization (http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle):
idxs[i] = 0;
for (var i:int = 1; i < items.length; i++)
{
rnd = int(Math.random() * (i + 1));
idxs[i] = idxs[rnd];
idxs[rnd] = rnd;
}
curIdx = 0;
priorItemIdx = -1;
}
private function randomize():void
{
var tempint:int;
//Fisher-Yates (http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle):
for (var i:int = items.length; i >= 1; i--)
{
rnd = int(Math.random() * (i + 1));
tempint = idxs[i];
idxs[i] = idxs[rnd];
idxs[rnd] = tempint;
}
curIdx = 0;
}
public function next():void
{
if (curIdx >= idxs.length)
{
randomize();
}
if (items.length > 1 && priorItemIdx == idxs[curIdx])
{
curIdx++;
}
priorItemIdx = idxs[curIdx++];
return items[priorItemIdx];
}
public function get items():Array
{
return _items;
}
public function set items(value:Array):void
{
_items = value;
initRandomize();
}
}
}
I would use a utility class like this to abstract out the behavior I wanted:
import flash.text.TextField;
class Randomizer {
private var unused:Array = [];
private var used:Array;
public function Randomizer(playList:Array) {
used = playList;
}
public function next():* {
// If almost empty, refill the unused array
if(unused.length <= 1) refill();
// Get the first item off the playList
var item:* = unused.shift();
// Shove it into the bucket
used.push(item);
// return it back
return item;
}
public function refill():void {
var i:int;
// Fisher-Yates shuffle to refill the unused array
while(used.length > 0) {
i = Math.floor(Math.random() * used.length)
unused.push(used.splice(i,1)[0])
}
}
}
Notice that it refills the unused array when the unused array still has one item in it, this makes it impossible for the last result to repeat twice in a row. This will return each item once before before looping, and will never repeat the same item twice.
You would use it by saying something like:
var ads:Randomizer = new Randomizer(["Image1", "Image2", "Image3"]);
ads.next(); // will return something
ads.next(); // will return something
ads.next(); // will return something
ads.next(); // will return something
// Keep going into infinity...
There is a little test example of this code working here.
See if this makes any sense
//create your array of all your ad names/frame labels
var PrepMCs:Array = new Array("Image1", "Image2", "Image3");
var shuffledMCs:Array = [];
//store the name of the last played ad in this var
var lastAdPlayed:String;
//shuffle the array
shuffleArray(PrepMCs);
function shuffleArray(arrayToShuffle:Array):void {
//clear the array
shuffledMCs = [];
var len:int = arrayToShuffle.length;
for(var i:int = 0; i<len; i++) {
shuffledMCs[i] = arrayToShuffle.splice(int(Math.random() * (len - i)), 1)[0];
}
//test to see if the new first ad is the same as the last played ad
if (lastAdPlayed == shuffledMCs[0]) {
//reshuffle
shuffleArray(PrepMCs);
} else {
lastAdPlayed = [0];
trace(shuffledMCs);
playAds();
}
}
//after each ad has played, call this function
function playAds():void {
if (shuffledMCs.length > 0) {
gotoAndPlay(shuffledMCs[0]);
shuffledMCs.splice(0,1);
} else {
//array is empty so we have played all the ads
shuffleArray(PrepMCs);
}
}

Creating a new array for eache iteration of the function call. AS3

so I have writing a function that returns objects on the stage and puts them into an array. and the function works fine until i call the function on more than one object name, meaning if im in the root class, and I call this function on object1 lets say it will add all the object one's from the stage, but if i call it on object2 it will throw an error, which makes some sense, i guess it means that it is not adding it to a unique array, but im not sure how to do that.
would it be a good idea to maybe make a multidimensional array? if that is the case would it be too slow?
here is the function code:
public function findObjects(objectName, objLocation, bVisible = false):Array{
for (var i = 0; i < objLocation.numChildren; i++){
var nObj=objLocation.getChildAt(i);
if (nObj is objectName){
// add to array and make invisible
obj.push(nObj);
nObj.visible=bVisible;
}
}
return obj;
}
any help with this would be greatly appreciated.
Try this:
public function findObjects(type:Class, target:DisplayObjectContainer, bVisible:Boolean=false):Array
{
var out:Array = [];
for(var i:int = 0; i<target.numChildren; i++)
{
var obj:DisplayObject = target.getChildAt(i);
if(obj is type)
{
out.push(obj);
obj.visible = bVisible;
}
}
return out;
}
And then based on your code, the implementation would probably be:
obj = findObjects(MovieClip, container);

flash as3 how to prevent an item from being added to an array if it already exists in the array

I know how to remove duplicates from an array, but what I'm trying to do is prevent an item from ever being added to an array in the first place if it already exists. I'm pulling in data from an xml feed in a loop, and I thought that searching for that values index would work, but no matter what, the index is always -1. Here's my code:
var yearArr:Array = new Array();
for (var i=0;i<numCovers;i++){
var coverRef = xmlObj.cover[i];
var coverClip:MovieClip = new MovieClip();
coverClip.year = coverRef.#year;
if (yearArr.indexOf(coverClip.year === -1)){
yearArr.push (coverClip.year);
}
}
Maybe I'm misunderstanding the indexOf function, but I thought it was supposed to return -1 if a value did not exist in an array. What am I doing wrong?
Here's the solution I came up with:
var yearArr:Array = new Array();
for (var i=0;i<numCovers;i++){
var coverRef = xmlObj.cover[i];
var coverClip:MovieClip = new MovieClip();
coverYear = coverRef.#year;
addCoverYear(coverYear);
}
function addCoverYear(coverYear:int):void {
if (yearArr.indexOf(coverYear) == -1){
yearArr.push(coverYear);
}
}
you can reduce an array by passing everything to a dictionary, which will automatically remove redundancies. then pass the dictionary back as a new array.
//Reduce Array
private function reduceArray(array:Array):Array
{
var dictionary:Dictionary = new Dictionary();
for each (var element:String in array)
dictionary[element] = true;
var result:Array = new Array();
for (var key:String in dictionary)
result.push(key);
dictionary = null;
return result;
}
Your code is almost fine. The problem is that an E4X property .#year is not a literal string (I'm not sure right now, but I believe it's an XMLList object). That's why the indexOf call will keep returning -1, because it is looking for a duplicate of that object, not a string. E4X will convert it to a string as soon as you put it somewhere where only strings can go, but until that time it is something else.
If you rewrite your code like this, it should work right away:
var yearArr:Array = new Array();
for each (var coverRef : XML in xmlObj.cover){
var year : String = coverRef.#year; // force the property to be a string
if (yearArr.indexOf(year) < 0){
yearArr.push (year);
}
}
There were also a few other optimizations you could do to your code. The new MovieClip() part wasn't used, not all variables were strongly typed and by using a for each loop, you can state much clearer what objects you're looping through.
Here is what you could do, if for example, you have an array of strings.
var ItemList:Array = new Array();
for each(var Item:String in UseYourXMLFeed)
{
if(ItemList.indexOf(Item) == -1)
{
ItemList.push(Item);
}
}
Edit:
Anyways, your real answer is in the comment by Sam.

How would I remove a "row" in an array depending on the value of an element?

Here's what I'm currently doing/trying to do to accomplish my goal. But it is not removing the "row" the way I would like it too.
So, I'm making an object, then pushing it into an array. And the adding to the array part works fine and just as I expect.
var nearProfileInfoObj:Object = new Object();
nearProfileInfoObj.type = "userInfo";
nearProfileInfoObj.dowhat = "add";
nearProfileInfoObj.userid = netConnection.nearID;
nearProfileInfoObj.username = username_input_txt.text;
nearProfileInfoObj.sex = sex_input_txt.selectedItem.toString();
nearProfileInfoObj.age = age_input_txt.selectedItem;
nearProfileInfoObj.location = location_input_txt.text;
nearProfileInfoObj.headline = headline_input_txt.text;
theArray.push(nearProfileInfoObj);
So after that later on I need to be able to remove that object from the array, and it's not working the way I'm expecting. I want to take a variable whoLeft and capture their ID and then look in the array for that particular ID in the userid part of the object and if its there DELETE that whole "row".
I know you can do a filter with an array collection but that doesnt actually delete it. I need to delete it because I may be adding the same value again later on.
whoLeft = theiruserIDVariable;
theArray.filter(userLeaving);
public function userLeaving(element:*, index:int, arr:Array):Boolean
{
if (element.userid == whoLeft)
{
return false;
}
else
{
return true;
}
}
But this doesnt seem to be deleting the whole row like it implies. Does anyone know what i'm doing wrong?
Instead of modifying the original array, the new filtered array is returned by the filter method. So you need to assign the returned array to theArray.
Try this
theArray = theArray.filter(userLeaving);
EDIT This turned out to be slower than for loop:
An alternative to the hand coded loop could be something like this:
theArray.every(searchAndDestroy);
public function searchAndDestroy(element:*, index:int, arr:Array):Boolean
{
if (element.userid == whoLeft)
{
arr.splice(index,1);
return false;
}
return true;
}
As far as I know, every() terminates the first time the test function returns false. So the question is: for a big list, which is faster, the for loop or the loop that every() does with the overhead of the test function call.
EDIT #2 But this was faster than a for loop for a test I ran on an array of a million Points:
for each(var element:Object in theArray)
{
if (element.userid==whoLeft)
{
theArray.splice(theArray.indexOf(element),1);
break;
}
}
I think this is what you're looking for:
for(var i:uint = 0, len:uint = theArray.length; i<len; i++)
{
if(thisArray[i].id == whoLeft.id)
{
thisArray.splice(i, 1);
break;
}
}
However, do you really need it in an Array because you could always use a Dictionary which would mean accessing it by id which would be a lot simpler to remove.

Resources