Create a new fixed size array in solidity - ethereum

What is the difference between the below two array?
without new keyword: bool[3] fixedArray;
with new keyword: bool[] fixedArray2 = new bool[](3);

The new keyword is used to initialise arrays in memory. From the docs:
Allocating Memory Arrays
Creating arrays with variable length in
memory can be done using the new keyword. As opposed to storage
arrays, it is not possible to resize memory arrays by assigning to the
.length member.
pragma solidity ^0.4.16;
contract C {
function f(uint len) public pure {
uint[] memory a = new uint[](7);
bytes memory b = new bytes(len);
// Here we have a.length == 7 and b.length == len
a[6] = 8;
}
}

Related

Errors when loading random movie clips from an array as3

I am getting closer to finding a solution for the errors being generated when running the code below.
I have three boxes on the stage. The goal is to load one random item from the array without any one item being duplicated in more than one of the three boxes.
Yasuyuki Uno has been very helpful. We are currently trying to solve the following:
Code:
var animalArray: Array = [animal1, animal2, animal3, animal4, animal5, animal6, animal7, animal8, animal9, animal10];
var randArr: Array = [];
var rand: int;
// Get random value for 3 times.
for(var i:int=0,len:int=animalArray.length;i<3;i++,len--){
rand = Math.floor( Math.random() * len); // Generate random integer between 0 and len-1.
randArr.push(animalArray.splice(rand,1)); // Delete a value from original array and add that value to new array.
}
box1.addChild(randArr[0]);
box2.addChild(randArr[1]);
box3.addChild(randArr[2]);
Error Message: Incorrect number of arguments. Expected no more than 0
Any help would be greatly appreciated. Thnx!
Assuming that animal1, animal2, etc are linkage IDs in your library, they are class references so they need to be instantiated using the new operator.
There are a few other non-critical issues with your code that made it hard to understand from my point of view:
Using animal1 instead of Animal1 and so on for class names. Uncapitalized names look like properties or functions, not classes.
Using Array instead of Vector. Vectors give you better errors; had you been using Vectors from the start your problem would be obvious.
Example:
var animalTypes:Vector.<Class> = new <Class>[Animal1, Animal2, Animal3, Animal4, Animal5, Animal6, Animal7, Animal8, Animal9, Animal10];
var randomAnimals:Vector.<DisplayObject> = new <DisplayObject>[];
// Get random value for 3 times.
for (var i:int = 0; i < 3; i++){
// Generate random integer between 0 and length-1.
var randomIndex:int = Math.random() * animalTypes.length;
// Remove a class from original vector.
var randomAnimalType:Class = animalTypes.splice(randomIndex, 1)[0];
// Create an instance of the animal class.
var randomAnimal:DisplayObject = new randomAnimalType();
// Add the instance to the random vector.
randomAnimals.push(randomAnimal);
}
box1.addChild(randomAnimals[0]);
box2.addChild(randomAnimals[1]);
box3.addChild(randomAnimals[2]);
As you check length of animalArray in for expression, it's no need to change variable len.
Also if you want to fill with 3 random items new array, you need to use this code:
const arr: Array = [animal1, animal2, animal3, animal4, animal5, animal6, animal7];
const genArr: Array = [];
var len: int = arr.length;
var n: int = 3;
while(n--) {
const randIndex: int = Math.floor(Math.random()*len); // get random index
genArr.push(arr.splice(randIndex, 1)[0]); // splice returns array, so we need first and exist item
len--; // decrement length as optimized solution of no-read length of array each cycle
}
trace(genArr);

Effective algorithm for finding value objects in collection

Suppose we have some custom object type:
class SomeObjectType {
public var intProperty1:int;
public var intProperty2:int;
public var intProperty3:int;
public var stringProperty1:String;
public var stringProperty2:String;
public var stringProperty3:String;
public var stringPropertyThatActuallyIsInt1:String;
public var stringPropertyThatActuallyIsInt2:String;
public var stringPropertyThatActuallyIsInt3:String;
...
%ABOUT_20_ANOTHER_PROPERTIES_THAT_I_WON'T_USE%
}
We have a collection of more than 20k instances of these objects. And we have just 1 text input that is actually search filter. User can type in this filter field anything he want and if his filter matches with ANY of first 9 fields I described before we should leave this object in collection. Just simple items filtering.
And let me describe how it works in our project now. This algorithm casts all these properties to Strings, concatenate them, and search using indexOf() != -1 method. This is really slow. It takes about 500-900ms on my dev machine and about 3-4s on iPad on every filter change. Horrible statistics, isn't it?
Small note: we use this algorithm in different 3 places in app and objects differs from object I described above but idea is same. I believe that it is a good idea to compare int to int, string to string (implementing some of fast algorithms(there are lots if them)), and convert string that is actually to int and compare them as int to int, but object differs a lot so I need some common algorithm.
If by collection you mean ArrayCollection, I would recommend to use Vector instead.
Vectors are around 50 times faster then ArrayCollections.
If you need databinding, you could have a look at VectorCollection, but I can't imagine the performance to be anywhere close to Vector.
Also if you are not extending class SomeObjectType anywhere, you could gain some performance (especially on iOS) by making it final class SomeObjectType.
You can use dictionary to search, I think it will much faster, you just need to init for one time.
var dict:Dictionary = new Dictionary();
//get properties,in you obj, they are intProperty1,intProperty2 etc,exclude prototype
var properties:Array = ObjectUtil.getClassInfo(SomeObjectType, ["prototype"]).properties as Array;
for each (var obj:SomeObjectType in yourArrayCollection) {
for (var i:int = 0; i < properties.length; i++) {
var qname:Object = properties[i];
var k:String = qname.localName;
var v:String = obj[k];
if (dict[v] == null) {
dict[v] = [];
}
//add only one time
if ((dict[v] as Array).indexOf(obj) == -1) {
(dict[v] as Array).push(obj);
}
}
}
So if you want return all objs contains "5", just return dict[5]

actionscript removing movieclip children

Ive got a document class in this class I dynamically create movie clips, store them in an array and finally add it to the stage using addChild. That's all fine, the issue is though im trying to remove the movieClips through the array and it is throwing an error:
1034: Type Coercion failed: cannot convert []#26be1fb1 to flash.display.DisplayObject.
Here is my code:
// Note i have declared the array outside the function, so that's not an issue
function x (e:MouseEvent){
if (thumbnails.length !== 0){ // Determine if any movieclips have already been created on stage and delete them
for(var ctr:int = 0; ctr < thumbnails.length;ctr++ ){
removeChild(thumbnails[ctr]);
}
}
for (var i: int = 0;i < userIput; i++){ // Loop through and create instances of symbol
var thumb:Thumbnail = new Thumbnail();
thumb.y = 180; // Set y position
thumb.x = 30 + ((thumb.width + 10) * i);
addChild(thumb);
thumbnails[i] = [thumb]; // Add to array
}
}
When you retrieve the MovieClip from your Array, you need to cast it as a DisplayObject before attempting to remove it:
if (thumbnails.length !== 0){ // Determine if any movieclips have already been created on stage and delete them
for(var ctr:int = 0; ctr < thumbnails.length;ctr++ ){
removeChild(DisplayObject(thumbnails[ctr]));
}
}
Alternatively, you could consider using a Vector (a type-safe version of an Array) with the base-type set as DisplayObject:
var thumbnails:Vector.<DisplayObject> = new Vector.<DisplayObject>();
thumbnails.push(new MovieClip());
this.addChild(thumbnails[0]);
this.removeChild(thumbnails[0]);
For further reading, have a look at the Adobe documentation on type conversion and Vectors.
Update:
Instead of adding an instance of Thumbnail to your Array the following line is actually adding a further Array containing a single element to your thumbnails Array (in effect you are creating a multi-dimensional Array):
// You're assigning an array literal with a single element
// to this element of the the thumbnails array
thumbnails[i] = [thumb];
Try either of the following instead:
// What you meant
thumbnails[i] = thumb;
// Better
thumbnails.push(thumb);
The error that appears tells you that Flash Player cannot convert []#26be1fb1 to DisplayObject. The []#26be1fb1 gives you a hint what type of object at which address cannot be converted. [] is the type of object here that means the type Array so when removeChild() is called you try to pass an array to it, but the method expects DisplayObject.
Why this happens
Your code has a very simple but maybe unobstrusive problem, namely at this code line:
thumbnails[i] = [thumb]; // Add to array
You put your thumb into an array by using [] around thumb. So what your code actually is doing is that it adds an array with a single element (thumb) to the array thumbnails. After that you have an array of arrays with single elements.
Solution
Change the above line to:
thumbnails[i] = thumb; // Add to array
This should solve your issue.
For your perceived issue:
Use Vector instead of Array
or cast array item to Thumbnail class
But the main culprit will probably be the fact you never clear the items from the array, you remove them from the parent/stage, but you do not remove them from the array… together with adding the items at a specific place in the array will cause erratic behavior:
you add them:
t[0] = item0_0
t[1] = item0_1
t[2] = item0_2
t[3] = item0_3
then remove item0_0, item0_1, item0_2, item0_3 from stage, but leave them in the array
next you add e.g. 2 new ones
t[0] = item1_0
t[1] = item1_1
so you have:
on stage:
item1_0
item1_1
in array:
t[0] = item1_0
t[1] = item1_1
t[2] = item0_2
t[3] = item0_3
This should be working:
var thumbnails:Vector.<Thumbnail> = new Vector.<Thumbnail>();
function x (e:MouseEvent) {
var thumb:Thumbnail;
for each(thumb in thumbnails){
removeChild(thumb);
}
thumbnails = new Vector.<Thumbnail>(); // clear Vector by re-initiating it
for (var i: int = 0;i < userIput; i++){
thumb = new Thumbnail();
// ...
addChild(thumb);
thumbnails.push(thumb);
}
}

AS3 not passing number by value, rather by reference?

I have this:
for (var i:int = 0; i < 3; i++) {
var newChoice:MainButton = new MainButton(function(){
trace(this["func" + i])} );
}
public function func0 ...
public function func1 ...
public function func2 ...
(When clicked, MainButton calls the function in the argument)
However, I get func3, which I assume is do to it finding the value of i. But shouldn't it pass by value since it's a number? How do I get the wanted result? Thanks
You're not passing anything, except the function itself (which is passed by reference).
What's happening is that the function creates a closure around the variable i, changing its lifetime. When the anonymous function is called, i is still in its original scope, but the loop has already finished, leaving i at 3.
So, the closure is essentially keeping i in the scope of the function even after the original, declaring function has finished.
Instead of closing over the variable, you wanted to close over the variable's value at the time the function is created. You can achieve this with an intermediate variable that's set only once before being closed over:
for (var i:int = 0; i < 3; i++) {
var j = i; // New variable each time through the loop; closure will close over a different variable each time (that happens to have the same name)
var newChoice:MainButton = new MainButton(function(){
trace(this["func" + j])} );
}

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.