What's a nice way to merge two sorted arrays in ActionScript (specifically ActionScript 3.0)? The resulting array should be sorted and without duplicates.
To merge (concatenate) arrays, use .concat().
Below are two examples of how you can concatenate arrays and remove duplicates at the same time.
More convenient way: (you can use ArrayUtil.createUniqueCopy() from as3corelib)
// from as3corelib:
import com.adobe.utils.ArrayUtil;
var a1:Array = ["a", "b", "c"];
var a2:Array = ["c", "b", "x", "y"];
var c:Array = ArrayUtil.createUniqueCopy(a1.concat(a2)); // result: ["a", "b", "c", "x", "y"]
Slightly faster way: (you can loop through the arrays yourself and use Array.indexOf() to check for duplicates)
var a1:Array = ["a", "b", "c"];
var a2:Array = ["c", "b", "x", "y"];
var a3:Array = ["a", "x", "x", "y", "z"];
var c:Array = arrConcatUnique(a1, a2, a3); // result: ["a", "b", "c", "x", "y", "z"]
private function arrConcatUnique(...args):Array
{
var retArr:Array = new Array();
for each (var arg:* in args)
{
if (arg is Array)
{
for each (var value:* in arg)
{
if (retArr.indexOf(value) == -1)
retArr.push(value);
}
}
}
return retArr;
}
This is kind of an simple algorithm to write. I would be surprised if there were a more direct way to do this in Actionscript.
function merge(a1:Array, a2:Array):Array {
var result:Array = [];
var i1:int = 0, i2:int = 0;
while (i1 < a1.length && i2 < a2.length) {
if (a1[i1] < a2[i2]) {
result.push(a1[i1]);
i1++;
} else if (a2[i2] < a1[i1]) {
result.push(a2[i2]);
i2++;
} else {
result.push(a1[i1]);
i1++;
i2++;
}
}
while (i1 < a1.length) result.push(a1[i1++]);
while (i2 < a2.length) result.push(a2[i2++]);
return result;
}
Using Array.indexOf to detect duplicates is going to be painfully slow if you have a List containing a large number of elements; a far quicker way of removing duplciates would be to throw the contents of the Array into a Set after concatenating them.
// Combine the two Arrays.
const combined : Array = a.concat(b);
// Convert them to a Set; this will knock out all duplicates.
const set : Object = {}; // use a Dictionary if combined contains complex types.
const len : uint = combined.length;
for (var i : uint = 0; i < len; i++) {
set[combined[i]] = true;
}
// Extract all values from the Set to produce the final result.
const result : Array = [];
for (var prop : * in set) {
result.push[prop];
}
If your program makes heavy use of Collections then if may be prudent to make use of one of the many AS3 Collections frameworks out there which provide a simple interface for manipulating data and will always take the optimal approach when it comes to the implementation.
AS3Commons Collections
Polygonal DS
function remDuplicates(_array:Array):void{
for (var i:int = 0; i < _array.length;++i) {
var index:int = _array.indexOf(_array[i]);
if (index != -1 && index != i) {
_array.splice(i--, 1);
}
}
}
Then for the "merge" use concat.
exemple :
var testArray:Array = [1, 1, 1, 5, 4, 5, 5, 4, 7, 2, 3, 3, 6, 5, 8, 5, 4, 2, 4, 5, 1, 2, 3, 65, 5, 5, 5, 5, 8, 4, 7];
var testArray2:Array = [1, 1, 1, 5, 4, 5, 5, 4, 7, 2, 3, 3, 6, 5, 8, 5, 4, 2, 4, 5, 1, 2, 3, 65, 5, 5, 5, 5, 8, 4, 7];
testArray.concat(testArray2);
trace(testArray);
remDuplicates(testArray);
trace(testArray);
Please follow the below step to get your answer:
Concat two array using "Concat" Methos.
New Array (concated) sort using "Sort" method which provided as API in Array Class
Make user defined function to remove duplicates (see below functions)
> function removeDuplicates(p_arr:Array):Array {
var ansArr:Array = new Array();
var len:uint = p_arr.length;
var i:uint = 0;
var j:uint = 0;
ansArr[j] = p_arr[i];
i++;
j++;
while(i<len)
{
if(ansArr[j] != p_arr[i])
{
ansArr[j] = p_arr[i];
j++;
}
i++;
}
return ansArr;
}
Returned "ansArr" will be sorted and without duplicate merged array of two array.
Related
i created three arrays and each of them has their own sets of questions in it. is it possible to shuffle that three arrays everytime the game starts? so that the user will have to answer different sets of question everytime he clicks for a new game.
See for example:
Randomize or shuffle an array
as3 random array - randomize array - actionscript 3
The second one has a nice cheeky little use of Array.sort():
var arr:Array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
function randomize (a:*, b:*):int
{
return (Math.random() > .5) ? 1 : -1;
}
trace(arr.sort(randomize));
To shuffle the 3 arrays you could create 3 other arrays that will serve to hold the shuffled values.
var arr1:Array = [1, 2, 3, 4, 5];
var sorted1:Array = new Array(arr1.length);
var arr2:Array = [1, 2, 3, 4, 5];
var sorted2:Array = new Array(arr2.length);
var arr3:Array = [1, 2, 3, 4, 5];
var sorted3:Array = new Array(arr3.length);
randomPos:Number = 0;
you could then create a function that takes the value from one array and place it into a new shuffled array.
function shuffleArray(x, y){
for(var i:int = 0; i < y.length; i++){
randomPos = int(Math.random() * x.length);
y[i] = x.splice(randomPos, 1)[0];
}
}
Then you would call the suffleArray function on each set of arrays:
shuffleArray(arr1, sorted1);
shuffleArray(arr2, sorted2);
shuffleArray(arr3, sorted3);
I hope this helps.
I have an array:
var type:Array = [[[1,2,3], [1,2,3],[1,2,3]],
[[1,2,3], [1,2,3],[1,2,3]]];
Then I loop it to call the a function:
for(var i:int = 0;i<type.length;i++) {
addGrid(type[0][i]);
}
The function that I'm calling is:
public function addGrid(col,row:int, type:Array) {
var newGird:GridE = new GirdE();
newGird.col = col;
newGird.row = row;
newGird.type = type;
}
Hope it clear what i need. My Gird can be a big as the array is for the Array sample in here the Gird would be 3(Columns)x2(Rows)
ActionScript 3 multidimensional arrays may be referenced using multiple array indexes by looping your row and column.
Per your array structure, you first define rows, then columns.
This makes a lookup for cell value:
grid[row][col]
Iterating all elements could be implemented as:
private var grid:Array = [[[ 1, 2, 3 ], [ 1, 2, 3 ], [ 1, 2, 3 ]],
[[ 1, 2, 3 ], [ 1, 2, 3 ], [ 1, 2, 3 ]]];
public function loop()
{
// for every row...
for (var row:uint = 0; row < grid.length; row++)
{
// for every column...
for (var col:uint = 0; col < grid[row].length; col++)
{
// your value of "1, 2, 3" in that cell can be referenced as:
// grid[row][col][0] = 1
// grid[row][col][1] = 2
// grid[row][col][2] = 3
// to pass row, col, and the value array to addGrid function:
addGrid(row, col, grid[row][col]);
}
}
}
public function addGrid(row:int, col:int, value:Array):void
{
/* ... */
}
I am implementing a simple dot product algorithm into actionscript 3.0 codes. Here is the basic example.
(1, 2, 3) • (7, 9, 11) = 1×7 + 2×9 + 3×11 = 58
I have a simple code here.
public var array1:Array = [1, 2, 3]; // 4, 10, 18
public var array2:Array = [4, 5, 6];
public var answer:Number = 0;
public function Algorithm()
{
multiply();
}
public function multiply()
{
var temp:Number = 0 ;
while (temp < array1.length)
{
answer = array1[temp] * array2[temp];
temp++;
}
trace(answer += answer);
}
But when I trace it..instead of 32, it goes 36... looks like it is adding 4 again for the last answer.
Its bugging me.
You are overwriting answer each time the array loops. The only value that is being stored is the last (3*6 = 18). In your trace you are effectively doubling that, giving you 36 every time. Try this:
answer = answer + ( array1[temp] * array2[temp] );
Then just trace answer at the end.
Using ActionScript 3, suppose I have an array of numbers, lets say: 1, 2, 3, 4, 5. Is there a way to easily search this array and return the index corresponding to an element that is >= 2.5 (which would be, 3, in this case), for example? I'm implementing this with a while and for loop, and seems pretty wordy. Thought there might be a method for this already, but haven't stumbled upon it in:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Array.html#every()
Otherwise, what would be a simple way to achieve it?
In case it helps, I'll use this to implement a straight-forward linear interpolation math routine, assuming one doesn't already exist I'm not aware of.
I'm not aware of any firstIndexOf in ActionScript.
You could add it to an ArrayUtil class:
Given the array:
var array:Array = [ 1, 2, 3, 4, 5 ];
Pass it to the ArrayUtil function:
public static function firstIndexOf(array:Array, value:Number):int
{
for(var i:uint = 0; i < array.length; i++)
{
if(array[i] >= value)
return i;
}
// if not found, return -1
return -1;
}
var t:Array = [4,9,1,2,3,5,6];
function something(base:Number, array:Array):int
{
var t:Array = array.slice();
var h:Number = int.MAX_VALUE;
var i:int = -1;
while(t.length > 0)
{
var l:Number = t.pop();
if(l >= base)
{
if(h > l)
{
h = l;
i = t.length;
}
}
}
return i;
}
trace(something(2, t)); // at index [3]
when comparing simple arrays, i use something like the following function to concatenate and remove duplicates:
//Merge
public function merge(a1:Array, a2:Array):Array
{
var result:Array = a1.concat(a2);
var dictionary:Dictionary = new Dictionary();
for each (var item:Object in result)
dictionary[item] = true;
result = new Array();
for (var key:Object in dictionary)
result.push(key);
dictionary = null;
return result;
}
however, this approach doesn't work on complex arrays.
is there a well known algorithm, or is it even possible to write a function of recursion that can compare a Vector.<Object> with another? one that will always work even if the some objects being compared have additional key/value pairs?
[EDIT]
to be more clear, using a dictionary to determine if items in a simple array only works on primitive data types (int, number, string, etc.) or object references, so the above example works if it's passed 2 arrays resembling something like this:
var arr1:Array = new Array(1, 2, 3, 4, 5);
var arr2:Array = new Array(8, 7, 6, 5, 4);
resulting in a merged array with the following values:
1, 2, 3, 8, 7, 6, 5, 4
in contrast, i'm asking if it's possible to pass a function 2 complex arrays or Vector.<Object> all containing unique objects that may have identical key/value pairs and remove redundencies in the resulting Vector.<Object>. for example:
var vec1:Vector.<Object> = new Vector.<Object>();
vec1.push({city:"Montreal", country:"Canada"});
vec1.push({city:"Halifax", country:"Canada"});
var vec2:Vector.<Object> = new Vector.<Object>();
vec2.push({city:"Halifax", country:"Canada"});
vec2.push({city:"Toronto", country:"Canada"});
merging the above 2 vector objects would result in the following vector by determining and removing objects with identical key/value pairs:
{city:"Montreal", country:"Canada"}
{city:"Halifax", country:"Canada"}
{city:"Toronto", country:"Canada"}
i'm searching for an algorithm which could handle the removal of these similar objects without having to know about their specific key/value names or how many key/value pairs there are within the object.
Sure you can, you can build a similar example with any type of Vector:
public function mergeObjectVectors(v1:Vector.<Object>,
v2:Vector.<Object>):Vector.<Object>
{
var dictionary:Dictionary = new Dictionary();
var concat:Vector.<Object> = v1.concat(v2);
var result:Vector.<Object> = new Vector.<Object>();
for each(var i:Object in concat)
{
if (!dictionary[i])
{
dictionary[i] = true;
result.push(i);
}
}
return result;
}
However if you plan on accepting vectors of any type, it's different:
public function testing():void
{
var v1:Vector.<Object> = new Vector.<Object>();
v1.push({name:"Object 1"});
v1.push({name:"Object 2"});
// Vector w duplicates
var v2:Vector.<Object> = new Vector.<Object>();
var o:Object = {name:"Object 3"};
v2.push(o);
v2.push(o);
v2.push(o);
var resultVector:Vector.<Object> = mergeAnything(v1, v2, Class(Vector.<Object>));
var resultArray:Array = mergeAnything(v1, v2, Array);
var resultObject:Object = mergeAnything(v1, v2, Object);
}
public function mergeAnything(o1:Object, o2:Object, resultClass:Class):*
{
var dictionary:Dictionary = new Dictionary();
var result:Object = new resultClass();
var i:int;
for each(var o:Object in o1)
{
if (!dictionary[o])
{
dictionary[o] = true;
result[i++] = o;
}
}
for each(o in o2)
{
if (!dictionary[o])
{
dictionary[o] = true;
result[i++] = o;
}
}
return result;
}
The first example will be more resource-efficient.
EDIT:
This should do it, try it with your example:
public function mergeObjectVectors(v1:Vector.<Object>, v2:Vector.<Object>):Vector.<Object>
{
var concat:Vector.<Object> = v1.concat(v2);
var result:Vector.<Object> = new Vector.<Object>();
var n:int = concat.length;
loop:for (var i:int = 0; i < n; i++)
{
var objectToAdd:Object = concat[i];
var m:int = result.length;
for (var j:int = 0; j < m; j++)
{
var addedObject:Object = result[j];
if (this.areObjectsIdentical(objectToAdd, addedObject))
{
continue loop;
}
}
result.push(objectToAdd);
}
return result;
}
private function areObjectsIdentical(o1:Object, o2:Object):Boolean
{
var numComparisons:int = 0;
for (var s:String in o1)
{
numComparisons++;
if (o1[s] != o2[s])
{
return false;
}
}
for (s in o2)
{
numComparisons--;
}
return !numComparisons;
}