Pandas Dataframe's query method can refer to variables in the environment by prefixing them with an ‘#’ character like #a, ex:
seq = [1,2,3,4]
df.query('col1.isin(#seq)')
The method df.query can access the calling context and assign the seq variable value to #seq. I want to add this function in JavaScript, but how to access the function calling context in JavaScript?
Pandas is built on Python, which is different from JavaScript. (You knew that, of course, but... 🙂)
If we had code like your example in JavaScript, there would be no way for the query function to access the value of the seq local variable (I'm assuming it's local, not global). It just has no way to reach it.
If we wanted similar functionality, we'd probably use a tagged template function:
seq = [1,2,3,4];
df.query`col1.isin(${seq})`;
(That's a tagged function call, one of two/three kinds of function calls in JavaScript that don't use ().)
That creates a template object and calls df.query with that template object and an argument for each substitution (${...}) in the template. The function still doesn't reach out and get it, it's the template literal (the bit in backticks) that gets the value, which is then passed to the function.
Just for illustration:
function logArray(label, array) {
console.log(label + ":");
array.forEach((element, index) => {
console.log(` ${index}: ${JSON.stringify(element)}`);
});
}
const df = {
query(template, ...args) {
logArray("template", template);
logArray("args", args);
}
};
const seq = [1,2,3,4];
df.query`col1.isin(${seq})`;
Note that what gets passed to the function is the actual array, not a string version of it, so we can use that array to see if col1 is in [1,2,3,4], like this:
const df = {
col1: 2,
query(template, ...args) {
// (You'd need to have some parser here for the DSL aspects
// of your query; this is just a hardcoded example)
if (template[1] === ".isin(") {
// In `${"col1"}.isin(${seq})`, args[0] will be the
// string "col1" and args[1] will be the array from
// `seq`
return args[1].includes(this[args[0]]);
} else {
throw new Error(`Unknown expression`);
}
}
};
let seq = [1,2,3,4];
let result = df.query`${"col1"}.isin(${seq})`;
console.log(result); // true, because df.col1 is 2 and that's
// in [1,2,3,4]
seq = [5,6,7,8];
result = df.query`${"col1"}.isin(${seq})`;
console.log(result); // false, because df.col1 is 2 and that's not
// in [5,6,7,8]
Related
I'm working on a course and I'm to return an array using .filter from an array of strings.
arr = ['tim','tom','taaaaaamy'];
const validUserNames = arr.filter(n => n.length < 10);
console.log(validUserNames);
While this works, the course does not let me use a global variable. How would I write this without declaring the array initially? Thanks.
This should suffice your requirements:
const validUserNames = (arr) => arr.filter(n => n.length < 10);
validUserNames(['tim','tom','taaaaaamy'])
Keep in mind that all values in your array actually have less then 10 characters.
Since the goal is to create a function "validUserNames" that can be used on some array of strings, returning an array of only the valid strings, you need a function that accepts a parameter, which is the array that the caller wants filtered.
The traditional/classic format declares and names the parameters in the function statement:
function validUserNames(names) {
...
}
In the functional style as in your attempt, using an arrow function the parameter is the left side of the arrow function declaration
const validUserNames = (names) => { the function body };
Then you use the parameter "names" in the place where your global "arr" is used.
As noted in the linked documentation, the parentheses around the parameter are not strictly necessary (depending on the arguments) so your function your wrote with the addition of a parameter to take the place of the global becomes this:
const validUserNames = names => names.filter(s => s.length < 10);
console.log( validUserNames(['tim','tom','taaaaaaxxxxxxmy']) );
console.log( validUserNames(['verylongname', 'fred', 'anothertoolongname', 'jeff']) );
not a front end SME....is there a javascript or backbone(_) equivalent of this java 8 lambda instead of looping over a JSON array and matching on "type"? :
{
"things": [
{
"type": "THE_OTHER_THING"
},
{
"type": "MY_THING"
}
]
}
.
thing theThing = things.stream().filter(x -> x.getType() == ThingType.MY_THING).findFirst().orElse(null);
Assuming you are looking to iterate through an array and only return objects with a given type, I would suggest the following:
For single or little use, you could simply create the function that asserts the type of your choice:
function isThing(jsonObject) {
return jsonObject.type === "THIS_THING";
}
Or to avoid hard coding:
var THING_TYPE = "THIS_THING";
function isThing(jsonObject) {
return jsonObject.type === THING_TYPE;
}
Then you can apply this function to an array using its filter method.
var filteredList = completeList.filter(isThing);
filter, as described on MDN Array.prototype.filter, takes a function as an argument and applies it to every element within the array. If the function returns true, the element is added to a new array. Once the passed function has been applied to each element, the filter function returns the new array.
The above choice may be practical if you are simply looking for one or two types. However, if you have many types for which you might want filters, you should consider abstracting this away slightly, like so:
function createFilterWithType(desiredType) {
// will return true if jsonObject is of desired type
var typeAsserter = function (jsonObject) {
return jsonObject.type === desiredType;
}
return typeAsserter;
}
// Create functions that assert if object is given type
var isThisThingType = createFilterWithType("THIS_THING");
var isOtherThingType = createFilterWithType("OTHER_THING");
// Data
var completeList = [
{type:"THIS_THING", id:0},
{type:"OTHER_THING", id:1}
];
// Data filtered by applying asserters to completeList
var thingTypeList = completeList.filter(isThisThingType);
// returns [{type:"THIS_THING", id:0}]
var otherTypeList = completeList.filter(isOtherThingType);
// returns [{type:"OTHER_THING", id:1}]
Alternatively, you can create the asserters and apply in a single step:
var thingTypeList = completeList.filter(createFilterWithType("THIS_THING"));
var otherTypeList = completeList.filter(createFilterWithType("OTHER_THING"));
Though you remove a few lines by doing so, you lose in performance as each invocation of filter requires the creation of the anonymous assertion function. Worse still, compacting your code this way can make it far more difficult to reason about.
I ran into this potential scenario that I posed to a few of my employees as a test question. I can think of a couple ways to solve this problem, but neither of them are very pretty. I was wondering what solutions might be best for this as well as any optimization tips. Here's the question:
Given some arbitrary string "mystr" in dot notation (e.g. mystr = "node1.node2.node3.node4") at any length, write a function called "expand" that will create each of these items as a new node layer in a js object. For the example above, it should output the following, given that my object name is "blah":
blah: { node1: { node2: { node3: { node4: {}}}}}
From the function call:
mystr = "node1.node2.node3.node4";
blah = {};
expand(blah,mystr);
Alternately, if easier, the function could be created to set a variable as a returned value:
mystr = "node1.node2.node3.node4";
blah = expand(mystr);
Extra credit: have an optional function parameter that will set the value of the last node. So, if I called my function "expand" and called it like so: expand(blah, mystr, "value"), the output should give the same as before but with node4 = "value" instead of {}.
In ES6 you can do it like this:
const expand = (str, defaultVal = {}) => {
return str.split('.').reduceRight((acc, currentVal) => {
return {
[currentVal]: acc
}
}, defaultVal)
}
const blah = expand('a.b.c.d', 'last value')
console.log(blah)
Here's a method that popped up in my mind. It splits the string on the dot notation, and then loops through the nodes to create objects inside of objects, using a 'shifting reference' (not sure if that's the right term though).
The object output within the function contains the full object being built throughout the function, but ref keeps a reference that shifts to deeper and deeper within output, as new sub-objects are created in the for-loop.
Finally, the last value is applied to the last given name.
function expand(str, value)
{
var items = mystr.split(".") // split on dot notation
var output = {} // prepare an empty object, to fill later
var ref = output // keep a reference of the new object
// loop through all nodes, except the last one
for(var i = 0; i < items.length - 1; i ++)
{
ref[items[i]] = {} // create a new element inside the reference
ref = ref[items[i]] // shift the reference to the newly created object
}
ref[items[items.length - 1]] = value // apply the final value
return output // return the full object
}
The object is then returned, so this notation can be used:
mystr = "node1.node2.node3.node4";
blah = expand(mystr, "lastvalue");
var obj = {a:{b:{c:"a"}}};
const path = "a.b.c".split(".");
while(path.length > 1){
obj = obj[path.shift()];
}
obj[path.shift()] = "a";
I've found this topic which I've implemented (see accepted answer):
javascript equivalent of PHP's call_user_func()
However, I am having a problem with multiple parameters. I realize what I was doing was turning my parameters into strings and treating it like 1 parameter, but I don't know how to fix this because I am dynamically creating the parameters.
Meaning, I have defined in my code the following:
var a = new Array();
a[0] = new Array();
a[0][0] = 'alert';
a[0][1] = '\'Hello World\'';
a[1] = new Array();
a[1][0] = 'setTimeout';
a[1][1] = 'alert("goodbye world")';
a[1][2] = '20';
Later, I was calling them like this:
var j = 0;
var len = 0;
var fx = '';
var params = '';
for( i in a ){
params = '';
len = a[i].length;
fx = a[i][0]; // getting the function name
a[i].splice( 0, 1 ); // removing it from array
if( len > 1 ){
params = a[i].join(", "); // trying to turn the parameters into the right format, but this is turning it into strings I think
params = params.replace(/\\'/g,'\''); // bc i was adding slashes with PHP
}
window[fx](params);
}
I don't have to use arrays to do this. I don't understand JS OOP (haven't tried yet), though I am comfortable with PHP OOP, so I don't know if there is a way to do this there.
Any help on passing multiple parameters would be appreciated.
Thanks.
First thing to do: Scrap your entire code, start over. Your approach will not get you anywhere where you'd want to be. (Unfortunately I can't tell you where you'd want to be because I cannot make sense of your example.)
There are three ways to call a function in JavaScript.
function foo() { console.log(arguments); }
// 1. directly
foo(1, 2, 3);
// 2. trough Function.call()
foo.call(this, 1, 2, 3);
// 3. trough Function.apply()
var args = [1, 2, 3];
foo.apply(this, args);
call and apply are similar. They let you decide which object the this keyword will point to inside the function (that's the important bit!).
apply accepts an array of arguments, call accepts individual arguments.
The closest thing to call() is PHP's call_user_func(). The closest thing to apply() is PHP's call_user_func_array().
JavaScript objects share something with PHP arrays: They are key/value pairs.
// an anonymous function assigned to the key "foo"
var obj = {
foo: function () { console.log(arguments); }
};
This means you can access object properties either with the dot notation:
// direct function call
obj.foo(1, 2, 3);
Or through square bracket notation (note that object keys are strings):
var funcName = "foo";
obj[funcName](1, 2, 3);
obj[funcName].call(obj, 1, 2, 3);
obj[funcName].apply(obj, [1, 2, 3]);
Square bracket notation gives you the freedom to choose an object property dynamically. If this property happens to be a function, apply() gives you the freedom to choose function arguments dynamically.
Every top-level function that has not been declared as the property of some object will become the property of the global object. In browsers the global object is window. (So the function foo() in my first code block above really is window.foo.)
Note that this does not work like in PHP. It will point to the object the function has been called on, not the object the function "belongs to". (The concept "belongs to" does not really exist in JavaScript. Things can be modeled that way, but it's only a convention.)
With direct calling (obj.foo(1, 2, 3)), this will point to obj. With call and apply, this will point to whatever object you want to. This is a lot more useful than it sounds at first. Most of the time when you want to call functions dynamically, you will end up using apply.
Check out Function.apply:
function test(a, b) { console.log([a, b]) }
test.apply(null, [1, 2]); // => [ 1, 2 ]
Late to the party, but now with ES6 you can simply do
function FunctionX(a,b,c,d){
return a + b + c + d;
}
let fx = "FunctionX";
let params = [ 1, 10, 100, 200 ];
let answer = window[fx]( ... params);
let answer2 = globalThis[fx]( ... params ); // this is more cross-platform
to unpack your argument array
this.String = {
Get : function (val) {
return function() {
return val;
}
}
};
What is the ':' doing?
this.String = {} specifies an object. Get is a property of that object. In javascript, object properties and their values are separated by a colon ':'.
So, per the example, you would call the function like this
this.String.Get('some string');
More examples:
var foo = {
bar : 'foobar',
other : {
a : 'wowza'
}
}
alert(foo.bar); //alerts 'foobar'
alert(foo.other.a) //alerts 'wowza'
Others have already explained what this code does. It creates an object (called this.String) that contains a single function (called Get). I'd like to explain when you could use this function.
This function can be useful in cases where you need a higher order function (that is a function that expects another function as its argument).
Say you have a function that does something to each element of an Array, lets call it map. You could use this function like so:
function inc (x)
{
return x + 1;
}
var arr = [1, 2, 3];
var newArr = arr.map(inc);
What the map function will do, is create a new array containing the values [2, 3, 4]. It will do this by calling the function inc with each element of the array.
Now, if you use this method a lot, you might continuously be calling map with all sorts of arguments:
arr.map(inc); // to increase each element
arr.map(even); // to create a list of booleans (even or odd)
arr.map(toString); // to create a list of strings
If for some reason you'd want to replace the entire array with the same string (but keeping the array of the same size), you could call it like so:
arr.map(this.String.Get("my String"));
This will create a new array of the same size as arr, but just containing the string "my String" over and over again.
Note that in some languages, this function is predefined and called const or constant (since it will always return the same value, each time you call it, no matter what its arguments are).
Now, if you think that this example isn't very useful, I would agree with you. But there are cases, when programming with higher order functions, when this technique is used.
For example, it can be useful if you have a tree you want to 'clear' of its values but keep the structure of the tree. You could do tree.map(this.String.Get("default value")) and get a whole new tree is created that has the exact same shape as the original, but none of its values.
It assigns an object that has a property "Get" to this.String. "Get" is assigned an anonymous function, which will return a function that just returns the argument that was given to the first returning function. Sounds strange, but here is how it can be used:
var ten = this.String["Get"](10)();
ten will then contain a 10. Instead, you could have written the equivalent
var ten = this.String.Get(10)();
// saving the returned function can have more use:
var generatingFunction = this.String.Get("something");
alert(generatingFunction()); // displays "something"
That is, : just assigns some value to a property.
This answer may be a bit superflous since Tom's is a good answer but just to boil it down and be complete:-
this.String = {};
Adds an object to the current object with the property name of String.
var fn = function(val) {
return function() { return(val); }
}
Returns a function from a closure which in turn returns the parameter used in creating the closure. Hence:-
var fnInner = fn("Hello World!");
alert(fnInner()); // Displays Hello World!
In combination then:-
this.String = { Get: function(val) {
return function() { return(val); }
}
Adds an object to the current object with the property name of String that has a method called Get that returns a function from a closure which in turn returns the parameter used in creating the closure.
var fnInner = this.String.Get("Yasso!");
alert(fnInner()); //displays Yasso!