Lets say I have an object
const obj = { width: 100, height: 200 }
I wish to pass that object to a method
myFunc( obj );
Inside that method I wish to pull out the height, but at the same time subtract a value. I only wish to do this once and after that it will never change.
Doing the following will get me the correct height I want of say 150.
let {height: localHeight} = obj;
localHeight = localHeight - 50;
How do I do the above in a single line ?
Something like this - but I know this doesn't work.
const { height: (localHeight = localHeight - 50) } = obj
It's possible, although it's a hack that hurts readability, might produce an error (if the object will contain the fake property in the future), and shouldn't be used in a real product.
You can destructure a non existing property, and use the default value to do the subtraction.
const obj = { width: 100, height: 200 }
const { height, localHeight = height - 50 } = obj
console.log(localHeight)
No, this is not possible. Destructuring does just that, it assigns properties to target expressions. Assignment syntax does not have any modifiers for altering the assigned value (default initialisers are already a stretch).
Just don't use destructuring and you get to do it in a single statement:
const localHeight = obj.height - 50;
Much shorter and less complicated than anything you could achieve with destructuring.
Related
I'm looking for way to generate data by JSON schema faker js with IDs incremented from 0.
When I'm trying to use autoIncrement parameter in schema, I get valid values, but this auto increment is started from random number.
Is that possible to do that with this package?
I didn't find an official solution to the problem, but here is a workaround.
json-schema-faker's source code for generating auto-incremented integers (node_modules\json-schema-faker\lib\index.js) explains why it starts from a random integer:
// safe auto-increment values
container.define('autoIncrement', function (value, schema) {
if (!this.offset) {
var min = schema.minimum || 1;
var max = min + env.MAX_NUMBER;
this.offset = random$1.number(min, max);
}
if (value === true) {
return this.offset++;
}
return schema;
});
It is the if (!this.offset) branch that sets up the initial value. To achieve our goal, we can modify the code inside the branch like this:
if (!this.offset) {
var min = schema.minimum || 1;
// var max = min + env.MAX_NUMBER;
// this.offset = random$1.number(min, max);
this.offset = min;
}
When minimum is specified in the schema, its value will be used as the starting point. Otherwise, 1 is used instead.
It is also noteworthy that, if you specify minimum with an extremely large number, the auto-incrementation will no longer be "safe".
For anyone searching for a more current answer, you can now set an 'initialOffset' value within the schema which acts as a start value
this question should be an easy one, but how do I replace an array or define it and then give it values based off a users choice. The code with the if statements below are some choices I need in one or both arrays.
For example
if(choice=="easy")
{
var sorted:Array = new Array("Beau","Dad","Jesus","Mary","Mom");
}
if(choice=="hard")
{
var sorted:Array = new Array("Beau","Dad","Jesus","Mary","Mom","Jordyn","Presley","Daddy","Mommy","Grandma","Grandpa","Nana","Gepa");
}
But this doesn't work above.
Thanks.
Declare the variable outside the condition instead (I also changed if/if to if/elseif as choice can't be both easy and hard at the same time):
var sorted:Array;
if(choice=="easy")
{
sorted = new Array("Beau","Dad","Jesus","Mary","Mom");
} else if(choice=="hard")
{
sorted = new Array("Beau","Dad","Jesus","Mary","Mom","Jordyn","Presley","Daddy","Mommy","Grandma","Grandpa","Nana","Gepa");
}
As an additional option to h2oooooo' answer , you can use something like:
var sorted:Array = {
"easy":["Beau","Dad","Jesus","Mary","Mom"],
"medium":["Jordyn","Presley","Jesus","Mary","Nana"],
"hard":["Beau","Dad","Jesus","Mary","Mom","Jordyn","Presley",
"Daddy","Mommy","Grandma","Grandpa","Nana","Gepa"]
}[choice];
trace(sorted.constructor); // [class Array]
I guess a step back is in order. My original question is at the bottom of this post for reference.
I am writing a word guessing game and wanted a way to:
1. Given a word length of 2 - 10 characters, randomly generate a valid english word to guess
2.given a 2 - 10 character guess, ensure that it is a valid english word.
I created a vector of 9 objects, one for each word length and dynamically created 172000
property/ value pairs using the words from a word list to name the properties and setting their value to true. The inner loop is:
for (i = 0; i < _WordCount[wordLength] - 2; i)
{
_WordsList[wordLength]["" + _WordsVector[wordLength][i++]] = true;
}
To validate a word , the following lookup returns true if valid:
function Validate(key:String):Boolean
{
return _WordsList[key.length - 2][key]
}
I transferred them from a vector to objects to take advantage of the hash take lookup of the properties. Haven't looked at how much memory this all takes but it's been a useful learning exercise.
I just wasn't sure how best to randomly choose a property from one of the objects. I was thinking of validating whatever method I chose by generating 1000 000 words and analyzing the statistics of the distribution.
So I suppose my question should really first be am I better off using some other approach such as keeping the lists in vectors and doing a search each time ?
Original question
Newbie first question:
I read a thread that said that traversal order in a for.. in is determined by a hash table and appears random.
I'm looking for a good way to randomly select a property in an object. Would the first element in a for .. in traversing the properties, or perhaps the random nth element in the iteration be truly random. I'd like to ensure that there is approximately an equal probability of accessing a given property. The Objects have between approximately 100 and 20000 properties. Other approaches ?
thanks.
Looking at the scenario you described in your edited question, I'd suggest using a Vector.<String> and your map object.
You can store all your keys in the vector and map them in the object, then you can select a random numeric key in the vector and use the result as a key in the map object.
To make it clear, take a look at this simple example:
var keys:Vector.<String> = new Vector.<String>();
var map:Object = { };
function add(key:String, value:*):void
{
keys.push(key);
map[key] = value;
}
function getRandom():*
{
var randomKey = keys[int(Math.random() * keys.length)];
return map[randomKey];
}
And you can use it like this:
add("a", "x");
add("b", "y");
add("c", "z");
var radomValue:* = getRandom();
Using Object instead of String
Instead of storing the strings you can store objects that have the string inside of them,
something like:
public class Word
{
public var value:String;
public var length:int;
public function Word(value:String)
{
this.value = value;
this.length = value.length;
}
}
Use this object as value instead of the string, but you need to change your map object to be a Dictionary:
var map:Dictionary = new Dictionary();
function add(key:Word, value:*):void
{
keys.push(key);
map[key] = value;
}
This way you won't duplicate every word (but will have a little class overhead).
Actually I've parsed a website using htmlparser and I would like to find a specific value inside the parsed object, for example, a string "$199", and keep tracking that element(by periodic parsing) to see the value is still "$199" or has changed.
And after some painful stupid searching using my eyes, I found the that string is located at somewhere like this:
price = handler.dom[3].children[3].children[3].children[5].children[1].
children[3].children[3].children[5].children[0].children[0].raw;
So I'd like to know whether there are methods which are less painful? Thanks!
A tree based recursive search would probably be easiest to get the node you're interested in.
I've not used htmlparser and the documentation seems a little thin, so this is just an example to get you started and is not tested:
function getElement(el,val) {
if (el.children && el.children.length > 0) {
for (var i = 0, l = el.children.length; i<l; i++) {
var r = getElement(el.children[i],val);
if (r) return r;
}
} else {
if (el.raw == val) {
return el;
}
}
return null;
}
Call getElement(handler.dom[3],'$199') and it'll go through all the children recursively until it finds an element without an children and then compares it's raw value with '$199'. Note this is a straight comparison, you might want to swap this for a regexp or similar?
My problem requires me to dynamically add where clauses to a IQueryable based on user input. The problem i'm having is that Linq-to-SQL doesn't seem to like having multiple where clauses on the same field, it actually duplicates the search arg value for the last item on all parameters. I verified this behavior through a SQL trace. Here is what I'm seeing.
WHERE ([t22].[OpenText] LIKE #p11) AND ([t22].[OpenText] LIKE #p12)
-- #p11: Input NVarChar (Size = 10; Prec = 0; Scale = 0) [%classify%] // Should be 2da57652-dcdf-4cc8-99db-436c15e5ef50
-- #p12: Input NVarChar (Size = 10; Prec = 0; Scale = 0) [%classify%]
My code uses a loop to dynamically add the where clauses as you can see below. My question is how do I work around this? This pretty much seems like a bug with the tool, no?
// add dyanmic where clauses based on user input.
MatchCollection searchTokens = Helper.ExtractTokensWithinBracePairs(filterText);
if (searchTokens.Count > 0)
{
foreach(Match searchToken in searchTokens)
query = query.Where((material => material.OpenText.Contains(searchToken.Value)));
}
else
{
query = query.Where((material => material.OpenText.Contains(filterText)));
}
Closing over the loop variable considered harmful! Change
foreach(Match searchToken in searchTokens) {
query = query.Where(
material => material.OpenText.Contains(searchToken.Value)
);
}
to
foreach(Match searchToken in searchTokens) {
Match token = searchToken;
query = query.Where(
material => material.OpenText.Contains(token.Value)
);
}
You are closing over the loop variable, which is considered harmful. To fix do this:
foreach(Match searchToken in searchTokens)
{
Match searchToken2 = searchToken;
// ^^^^^^^^^^^^ copy the value of the reference to a local variable.
query = query.Where(material => material.OpenText.Contains(searchToken2.Value));
// use the copy here ^^^^^^^^^^^^
}
The reason why your version doesn't work is that the query refers to the variable searchToken, not the value it had when the query was created. When the variable's value changes, all your queries see the new value.
I don't have enough rep to leave comments yet (or this would be a comment and not an answer) but the answers listed here worked for me.
However, I had to turn off compiler optimizations in order for it to work. If you do not turn off compiler optimizations (at least at the method level) then the compiler sees you setting a loop variable to a local variable and throws the local variable away.