var b = "pp.specifications.full_specs.";
var c = arr[i];
here the value of arr[i] is Memory
var a = b+c;
console.log(a);
it prints pp.specifications.full_specs.Memory on console
but when I use
console.log(pp.specifications.full_specs.Memory);
then prints an json object as:
{ Series: 'Inspiron',
Model: 'A562103SIN9',
Utility: 'Everyday Use',
OS: 'Windows 10 Home (64-bit)',
Dimensions: '274.73 x 384.9 x 25.44 mm',
Weight: '2.62 Kg',
Warranty: '1 Year Onsite Warranty' }
whenever the value of a contains pp.specifications.full_specs.Memory;
So what is the reason for getting different outputs?
There's a elementary difference between
console.log(pp.specifications.full_specs.Memory);
and
console.log("pp.specifications.full_specs.Memory");
Note the quotes!
So the expression: console.log(pp.specifications.full_specs.Memory); can be read from left to right:
Print to the output value of pp.specifications.full_specs.Memory and this is a value of pp object after taking its property specifications and then its property full_specs etc.
And the "pp.specifications.full_specs.Memory" means only a piece of text.
What is happening in your code should now be clearer:
// B is piece of text
var b = "pp.specifications.full_specs.";
// C is some other value - let's say also textual one
var c = arr[i]
// So b+c will mean add text to some other text
// It's expected that the result of such operations is concatenated text
// So then console.log(b+c) will mean
// Print the concatenated text from b and c
// And it's just plain text
console.log(b+c);
//It's the same as:
console.log("pp.specifications.full_specs.Memory");
// And this one means print some specific object attributes
// which is different operation!
console.log(pp.specifications.full_specs.Memory);
If you want to access objects by text you can do the following:
var d = eval(b+c);
It's pretty dangerous and eval should be avoided but I just wanted to demonstrate the basic idea. Eval executes strings as if they were code.
So string "pp.specifications.full_specs.Memory" will be evaluates (yep!) as value of the actual object.
As The eval can execute anything it should be always avoided and moreover it's superslow!
Instead if you want to access some property of pp basic on some text input you can do:
pp['specifications']['full_specs']['Memory']
As the pp.x notation is equivalent to expression: pp['x']
I hope my answer will help you understand Javascript mechanisms better :)
Related
How do I convert the data type if I know the Variant.Type from typeof()?
for example:
var a=5;
var b=6.9;
type_cast(b,typeof(a)); # this makes b an int type value
How do I convert the data type if I know the Variant.Type from typeof()?
You can't. GDScript does not have generics/type templates, so beyond simple type inference, there is no way to specify a type without knowing the type.
Thus, any workaround to cast the value to a type only known at runtime would have to be declared to return Variant, because there is no way to specify the type.
Furthermore, to store the result on a variable, how do you declare the variable if you don't know the type?
Let us have a look at variable declarations. If you do not specify a type, you get a Variant.
For example in this code, a is a Variant that happens to have an int value:
var a = 5
In this other example a is an int:
var a:int = 5
This is also an int:
var a := 5
In this case the variable is typed according to what you are using to initialized, that is the type is inferred.
You may think you can use that like this:
var a = 5
var b := a
Well, no. That is an error. "The variable type can't be inferred". As far as Godot is concerned a does not have a type in this example.
I'm storing data in a json file: { variable:[ typeof(variable), variable_value ] } I added typeof() because for example I store an int but when I reassign it from the file it gets converted to float (one of many other examples)
It is true that JSON is not good at storing Godot types. Which is why many authors do not recommend using JSON to save state.
Now, be aware that we can't get a variable with the right type as explained above. Instead we should try to get a Variant of the right type.
If you cannot change the serialization format, then you are going to need one big match statement. Something like this:
match type:
TYPE_NIL:
return null
TYPE_BOOL:
return bool(value)
TYPE_INT:
return int(value)
TYPE_REAL:
return float(value)
TYPE_STRING:
return str(value)
Those are not all the types that a Variant can hold, but I think it would do for JSON.
Now, if you can change the serialization format, then I will suggest to use str2var and var2str.
For example:
var2str(Vector2(1, 10))
Will return a String value "Vector2( 1, 10 )". And if you do:
str2var("Vector2( 1, 10 )")
You get a Variant with a Vector2 with 1 for the x, and 10 for the y.
This way you can always store Strings, in a human readable format, that Godot can parse. And if you want to do that for whole objects, or you want to put them in a JSON structure, that is up to you.
By the way, you might also be interested in ResourceFormatSaver and ResourceFormatLoader.
We have a "user script" where the goal is to check if a value is in a list.
The input values can be either int or double:
int i = 5
double d = 5
println i==d // gives true
But
println d in [5] // gives false
I understand why, int.equals(double ..) is false.
But is there a solution where the user can put ints or doubles in the list without considering the type?
But is there a solution where the user can put ints or doubles in the
list without considering the type?
There are, and what is the right thing to do would depend on understanding more about the data, but one option is instead of d in [5] you could do something like [5].any{ it == d }.
I am reading the Groovy closure documentation in https://groovy-lang.org/closures.html#this. Having a question regarding with GString behavior.
Closures in GStrings
The document mentioned the following:
Take the following code:
def x = 1
def gs = "x = ${x}"
assert gs == 'x = 1'
The code behaves as you would expect, but what happens if you add:
x = 2
assert gs == 'x = 2'
You will see that the assert fails! There are two reasons for this:
a GString only evaluates lazily the toString representation of values
the syntax ${x} in a GString does not represent a closure but an expression to $x, evaluated when the GString is created.
In our example, the GString is created with an expression referencing x. When the GString is created, the value of x is 1, so the GString is created with a value of 1. When the assert is triggered, the GString is evaluated and 1 is converted to a String using toString. When we change x to 2, we did change the value of x, but it is a different object, and the GString still references the old one.
A GString will only change its toString representation if the values it references are mutating. If the references change, nothing will happen.
My question is regarding the above-quoted explanation, in the example code, 1 is obviously a value, not a reference type, then if this statement is true, it should update to 2 in the GString right?
The next example listed below I feel also a bit confusing for me (the last part)
why if we mutate Sam to change his name to Lucy, this time the GString is correctly mutated??
I am expecting it won't mutate?? why the behavior is so different in the two examples?
class Person {
String name
String toString() { name }
}
def sam = new Person(name:'Sam')
def lucy = new Person(name:'Lucy')
def p = sam
def gs = "Name: ${p}"
assert gs == 'Name: Sam'
p = Lucy. //if we change p to Lucy
assert gs == 'Name: Sam' // the string still evaluates to Sam because it was the value of p when the GString was created
/* I would expect below to be 'Name: Sam' as well
* if previous example is true. According to the
* explanation mentioned previously.
*/
sam.name = 'Lucy' // so if we mutate Sam to change his name to Lucy
assert gs == 'Name: Lucy' // this time the GString is correctly mutated
Why the comment says 'this time the GString is correctly mutated? In previous comments it just metioned
the string still evaluates to Sam because it was the value of p when the GString was created, the value of p is 'Sam' when the String was created
thus I think it should not change here??
Thanks for kind help.
These two examples explain two different use cases. In the first example, the expression "x = ${x}" creates a GString object that internally stores strings = ['x = '] and values = [1]. You can check internals of this particular GString with println gs.dump():
<org.codehaus.groovy.runtime.GStringImpl#6aa798b strings=[x = , ] values=[1]>
Both objects, a String one in the strings array, and an Integer one in the values array are immutable. (Values are immutable, not arrays.) When the x variable is assigned to a new value, it creates a new object in the memory that is not associated with the 1 stored in the GString.values array. x = 2 is not a mutation. This is new object creation. This is not a Groovy specific thing, this is how Java works. You can try the following pure Java example to see how it works:
List<Integer> list = new ArrayList<>();
Integer number = 2;
list.add(number);
number = 4;
System.out.println(list); // prints: [2]
The use case with a Person class is different. Here you can see how mutation of an object works. When you change sam.name to Lucy, you mutate an internal stage of an object stored in the GString.values array. If you, instead, create a new object and assigned it to sam variable (e.g. sam = new Person(name:"Adam")), it would not affect internals of the existing GString object. The object that was stored internally in the GString did not mutate. The variable sam in this case just refers to a different object in the memory. When you do sam.name = "Lucy", you mutate the object in the memory, thus GString (which uses a reference to the same object) sees this change. It is similar to the following plain Java use case:
List<List<Integer>> list2 = new ArrayList<>();
List<Integer> nested = new ArrayList<>();
nested.add(1);
list2.add(nested);
System.out.println(list2); // prints: [[1]]
nested.add(3);
System.out.println(list2); // prints: [[1,3]]
nested = new ArrayList<>();
System.out.println(list2); // prints: [[1,3]]
You can see that list2 stores the reference to the object in the memory represented by nested variable at the time when nested was added to list2. When you mutated nested list by adding new numbers to it, those changes are reflected in list2, because you mutate an object in the memory that list2 has access to. But when you override nested with a new list, you create a new object, and list2 has no connection with this new object in the memory. You could add integers to this new nested list and list2 won't be affected - it stores a reference to a different object in the memory. (The object that previously could be referred to using nested variable, but this reference was overridden later in the code with a new object.)
GString in this case behaves similarly to the examples with lists I shown you above. If you mutate the state of the interpolated object (e.g. sam.name, or adding integers to nested list), this change is reflected in the GString.toString() that produces a string when the method is called. (The string that is created uses the current state of values stored in the values internal array.) On the other hand, if you override a variable with a new object (e.g. x = 2, sam = new Person(name:"Adam"), or nested = new ArrayList()), it won't change what GString.toString() method produces, because it still uses an object (or objects) that is stored in the memory, and that was previously associated with the variable name you assigned to a new object.
That's almost the whole story, as you can use a Closure for your GString evaluation, so in place of just using the variable:
def gs = "x = ${x}"
You can use a closure that returns the variable:
def gs = "x = ${-> x}"
This means that the value x is evaluated at the time the GString is changed to a String, so this then works (from the original question)
def x = 1
def gs = "x = ${-> x}"
assert gs == 'x = 1'
x = 2
assert gs == 'x = 2'
Here is a Python-like pattern I need to re-create in Chapel.
class Gambler {
var luckyNumbers: [1..0] int;
}
var nums = [13,17,23,71];
var KennyRogers = new Gambler();
KennyRogers.luckyNumbers = for n in nums do n;
writeln(KennyRogers);
Produces the run-time error
Kenny.chpl:8: error: zippered iterations have non-equal lengths
I don't know how many lucky numbers Kenny will have in advance and I can't instantiate Kenny at that time. That is, I have to assign them later. Also, I need to know when to hold them, know when to fold them.
This is a good application of the array.push_back method. To insert lucky numbers one at a time you can do:
for n in nums do
KennyRogers.luckyNumbers.push_back(n);
You can also insert the whole array in a single push_back operation:
KennyRogers.luckyNumbers.push_back(nums);
There are also push_front and insert methods in case you need to put elements at the front or at arbitrary positions in the array.
I don't think I can help on when to hold them or when to fold them.
A way to approach this that simply makes things the right size from the start and avoids resizing/rewriting the array is to establish luckyNumbers in the initializer for Gambler. In order to do this without resizing, you'll need to declare the array's domain and set it in the initializer as well:
class Gambler {
const D: domain(1); // a 1D domain field representing the array's size
var luckyNumbers: [D] int; // declare lucky numbers in terms of that domain
proc init(nums: [?numsD] int) {
D = numsD; // make D a copy of nums's domain; allocates luckyNumbers to the appropriate size
luckyNumbers = nums; // initialize luckyNumbers with nums
super.init(); // mark the initialization of fields as being done
}
}
var nums = [13,17,23,71];
var KennyRogers = new Gambler(nums);
writeln(KennyRogers);
This question already has answers here:
Create variables with names from strings
(6 answers)
Closed 6 years ago.
I have a loop running on multiple workstations, each loop is dealing with 5 different classes, when the results is acquired it is to save the result with the name of the classes it used.
For example on workstation 1 I am using:
class1 = 1;
class2 = 10;
%code that will run on all images associated with classes 1:10
% final_result from all 10 classes is calculated here
I want to save this now, with the name such as:
result_1_10 = final_result;
save result_1_10 result_1_10;
I can do this manually but its becoming very difficult to change the values on all machines after one value is changed, I would rather it save these and pick up the numbers from the two variables class1 and class2.
Here is what I tried:
['result_' num2str(class1) '_' num2str(class2)];
This would give me result_1_10. Which is what I wanted but it is a string, rather than a variable, so I cannot assign the result value to it
['result_' num2str(class1) '_' num2str(class2)] = final_result;
Would give the error:
Error: An array for multiple LHS assignment cannot contain
LEX_TS_STRING.
I even tried str2num(num2str(class1)) but that would also give an error.
How do I actually do this?
Thank you
While you can do this, it is very much discouraged by The Mathworks themselves. Any time you are trying to store information about what a variable contains within the variable name itself, that's a sign that maybe things should be rearranged a bit. Maybe consider using a different data structure.
Consider for example using a struct where you keep the classes as fields and the result as a field.
S.class1 = 1;
S.class2 = 10;
S.result = final_result;
You could then even create an array of structs holding your data.
S = struct('class1', {1, 2, 1}, ...
'class2', {10, 11, 10}, ...
'result', {rand(10), rand(10), rand(10)});
Then you could grab all results when class1 was 1:
S([S.class1 == 1]);
Or all results when class1 as 1 and class2 was 10
S([S.class1 == 1] & [S.class2 == 10]);
If you insist on doing it the way that you've laid out, you'll have to use eval or assignin to do that. Also, sprintf is often more concise than string concatenations.
variable = sprintf('result_%d_%d', class1, class2);
eval([variable, '= final_result;']);