How to Use Variables Newly Created in 'J' in the Same 'J' Argument

Using data.table i and j arguments in functions

Gavin and Josh are right. This answer is only to add more background. The idea is that not only can you pass variable column names into a function like that, but expressions of column names, using quote().

group = quote(car)
mtcars[, list(Total=length(mpg)), by=group][order(group)]
group Total
AMC 1
Cadillac 1
...
Toyota 2
Valiant 1
Volvo 1

Although, admitedly more difficult to start with, it can be more flexible. That's the idea, anyway. Inside functions you need substitute(), like this :

tableOrder = function(x,.expr) {
.expr = substitute(.expr)
ans = x[,list(Total=length(mpg)),by=.expr]
setkeyv(ans, head(names(ans),-1)) # see below re feature request #1780
ans
}

tableOrder(mtcars, car)
.expr Total
AMC 1
Cadillac 1
Camaro 1
...
Toyota 2
Valiant 1
Volvo 1

tableOrder(mtcars, substring(car,1,1)) # an expression, not just a column name
.expr Total
[1,] A 1
[2,] C 3
[3,] D 3
...
[8,] P 2
[9,] T 2
[10,] V 2

tableOrder(mtcars, list(cyl,gear%%2)) # by two expressions, so head(,-1) above
cyl gear Total
[1,] 4 0 8
[2,] 4 1 3
[3,] 6 0 4
[4,] 6 1 3
[5,] 8 1 14

A new argument keyby was added in v1.8.0 (July 2012) making it simpler :

tableOrder = function(x,.expr) {
.expr = substitute(.expr)
x[,list(Total=length(mpg)),keyby=.expr]
}

Comments and feedback in the area of i,j and by variable expressions are most welcome. The other thing you can do is have a table where a column contains expressions and then look up which expression to put in i, j or by from that table.

Why are variables i and j used for counters?

It comes ultimately from mathematics: the summation notation traditionally uses i for the first index, j for the second, and so on. Example (from http://en.wikipedia.org/wiki/Summation):

\sum_{i=1}^{n} i = \frac{n^2 + n}{2}

It's also used that way for collections of things, like if you have a bunch of variables x1, x2, ... xn, then an arbitrary one will be known as xi.

As for why it's that way, I imagine SLaks is correct and it's because I is the first letter in Index.

r data.table - can we use shift() on newly created columns

One possible solution is to calculate c and d within {}:

x <- data.table(a=c(1,2,3), b=c(4,5,6))

x[,c("c","d"):=({c=a*b; d=shift(c,-1); list(c,d)})][]

a b c d
1: 1 4 4 10
2: 2 5 10 18
3: 3 6 18 NA

How do I put variables inside javascript strings?

Note, from 2015 onwards, just use backticks for templating

https://stackoverflow.com/a/37245773/294884

let a = `hello ${name}`    // NOTE!!!!!!!! ` not ' or "

Note that it is a backtick, not a quote.


If you want to have something similar, you could create a function:

function parse(str) {
var args = [].slice.call(arguments, 1),
i = 0;

return str.replace(/%s/g, () => args[i++]);
}

Usage:

s = parse('hello %s, how are you doing', my_name);

This is only a simple example and does not take into account different kinds of data types (like %i, etc) or escaping of %s. But I hope it gives you some idea. I'm pretty sure there are also libraries out there which provide a function like this.

Newly added column in 'j' of data.table should be available in the scope

You can create and assign objects in j, just use { curly braces }.

You can then pass these objects (or functions & calculations of the objects) out of j and assign them as columns of the data.table. To assign more than once column at a time, simply:

  • wrap the LHS in c(.) make sure column names are strings and
  • the last line of j (ie, the "return" value) should be a list.

  dat[ , c("NewIncomeComlumn", "AnotherNewColumn") := { 
RelativeIncome <- Income/.SD[Nation == "A", Income];
RelativeIncomeLog2 <- log2(RelativeIncome);
## this last line is what will be asigned.
list(RelativeIncomeLog2 * 100, c("A", "hello", "World"))
# assigned values are recycled as needed.
# If the recycling does not match up, a warning is issued.
}
, by = list(Name, Nation)
]

You can losely think of j as a function within the environment of dat

You can also get a lot more sophisticated and complex if required. You can also incorporate by arguments as well, using by=list(<someName>=col)

In fact, similar to functions, simply creating an object in j and assigning it a value, does not mean that it will be available outside of j. In order for it to be assigned to your data.table, you must return it. j automatically returns the last line; if that last line is a list, each element of the list will be handled as a column. If you are assigning by reference (ie, using := ) then you will achieve the results you are expecting.


On a separate note, I noticed the following in your code:

 Income / .SD[Nation == "America", Income]

# Which instead could simply be:
Income / Income[Nation == "America"]

.SD is great in that it is a wonderful shorthand. However, to invoke it without needing all of the columns which it encapsulates is to burden your code with extra memory costs. If you are using only a single column, consider naming that column explicitly or perhaps add the .SDcols argument (after j) and being naming the columns needed there.

Pass variables by reference in JavaScript

There is no "pass by reference" available in JavaScript. You can pass an object (which is to say, you can pass-by-value a reference to an object) and then have a function modify the object contents:

function alterObject(obj) {
obj.foo = "goodbye";
}

var myObj = { foo: "hello world" };

alterObject(myObj);

alert(myObj.foo); // "goodbye" instead of "hello world"

You can iterate over the properties of an array with a numeric index and modify each cell of the array, if you want.

var arr = [1, 2, 3];

for (var i = 0; i < arr.length; i++) {
arr[i] = arr[i] + 1;
}

It's important to note that "pass-by-reference" is a very specific term. It does not mean simply that it's possible to pass a reference to a modifiable object. Instead, it means that it's possible to pass a simple variable in such a way as to allow a function to modify that value in the calling context. So:

 function swap(a, b) {
var tmp = a;
a = b;
b = tmp; //assign tmp to b
}

var x = 1, y = 2;
swap(x, y);

alert("x is " + x + ", y is " + y); // "x is 1, y is 2"

In a language like C++, it's possible to do that because that language does (sort-of) have pass-by-reference.

edit — this recently (March 2015) blew up on Reddit again over a blog post similar to mine mentioned below, though in this case about Java. It occurred to me while reading the back-and-forth in the Reddit comments that a big part of the confusion stems from the unfortunate collision involving the word "reference". The terminology "pass by reference" and "pass by value" predates the concept of having "objects" to work with in programming languages. It's really not about objects at all; it's about function parameters, and specifically how function parameters are "connected" (or not) to the calling environment. In particular, note that in a true pass-by-reference language — one that does involve objects — one would still have the ability to modify object contents, and it would look pretty much exactly like it does in JavaScript. However, one would also be able to modify the object reference in the calling environment, and that's the key thing that you can't do in JavaScript. A pass-by-reference language would pass not the reference itself, but a reference to the reference.

edit — here is a blog post on the topic. (Note the comment to that post that explains that C++ doesn't really have pass-by-reference. That is true. What C++ does have, however, is the ability to create references to plain variables, either explicitly at the point of function invocation to create a pointer, or implicitly when calling functions whose argument type signature calls for that to be done. Those are the key things JavaScript doesn't support.)

How can I add a variable to console.log?

Then use + to combine strings:

console.log("story " + name + " story");

How can I evaluate (or create) an on the fly column in data.table in r

You can also use <- within the call to list eg

DT <- data.table(a=1:5)

DT[, c('b','d') := list(b1 <- a*2, b1*3)]
DT
a b d
1: 1 2 6
2: 2 4 12
3: 3 6 18
4: 4 8 24
5: 5 10 30

Or

DT[, `:=`(hope = hope <- a+1, z = hope-1)]
DT
a b d hope z
1: 1 2 6 2 1
2: 2 4 12 3 2
3: 3 6 18 4 3
4: 4 8 24 5 4
5: 5 10 30 6 5


Related Topics



Leave a reply



Submit