stretchr
stretchr

Reputation: 615

Interpret line of Q code

Trying to understand what this function does:

yr:{ yr:.z.T+1000*x; -1 string .z.Z; while[(.z.T < yr); ZZ,::.z.Z]}

I understand .z.Z gets the datetime, and that execution is from right to left. what is ZZ? What is .z.T?

Essentially, what does the line accomplish?

Upvotes: 1

Views: 369

Answers (4)

Rahul
Rahul

Reputation: 3969

What This Function is doing:
This function accepts one parameter(should be int) and add those many seconds to current time(lets say it future time). Then it starts a loop from current time to future time and in every iteration, append current date and time to global list(referred by variable ZZ).

How to Call: yr[2]

Explanation:

yr:.z.T+1000*x
  • .z.T give you current local time.

  • 1000 is equivalent to 1 seconds. So it is adding x seconds to current time and storing it in variable yr. ( : means assignment (=))

ZZ,::.z.Z
  • :: is used to assign something to global variable. So ZZ is a global variable which is list (like array).

  • , is used to append. Above statement is equivalent to ZZ : ZZ , .z.Z

  • .z.Z gives current local date and time.

while[(.z.T < yr);...]
  • This is a condition for the loop. So it takes the current time(.z.T) and check whether it is lesser than future time that was calculated in first statement.

  • Loop will end once current time =yr(future time).

  • Finally you'll have global list which you can access using variable ZZ.

Upvotes: 0

JPC
JPC

Reputation: 1919

There is a nicer rewrite of this to make it much more idiomatic. It takes advantage of the overload of \ to iterate. Check out http://code.kx.com/q/ref/adverbs/#converge-iterate

The current function you have, takes the current time (.z.T) and adds x number of seconds (it multiplies by 1000 to make it milliseconds). This becomes your bound, and then as long as the current time is less than that, you append .z.Z (the datetime marker) to a global list ZZ.

The version below will do the same with a couple advantages:you avoid using a global and you write more idiomatic code

f2:{{.z.Z}\[{y; .z.T<x}.z.T+1e3*x; .z.Z]}

While your condition {y; .z.T<x}.z.T+1e3*x is true, your loop will continue to iterate. Note that we make sure to pass in the time limit from outside, so that it is not revaluated it each time, additionally we need a dummy parameter y, as it will try to apply this condition to the result of our iteration, but we don't really want that, since that is .z.Z. Each time it iterates it will evaluate .z.Z returning the datetime. Since you are using \ and not / you will get the entire list generated.

q)f2:{{.z.Z}\[{y; .z.T<x}.z.T+1e3*x; .z.Z]}
q)f2 1
2014.04.30T17:40:23.357 2014.04.30T17:40:23.357 .......

That being said, if you're looking to generate a sequence of datetime values, from now to now+x, this is not the best way to do that, since your .z.Z stamp will reflect the time it takes your machine to actually evaluate that.

CORRECTION: I did not correctly explain the reason our condition testing lambda is {y; .z.T<x}.z.T+1e3*x. You want to make sure your .z.T+1e3*x is only evaluated at the start, so you do not want your bound to be inside the function. Additionally, if you were to leave out the y param, then {z.T<x}.z.T+1e3*x would immediately evaluate to false, and your iteration would return a type error as it tries to apply your iteration result to 0b at each cycle of the loop. By keeping y and just not using it, we make sure to delay this evaluation and create a lambda that correctly tests our bound.

Upvotes: 1

Aaron Davies
Aaron Davies

Reputation: 1230

  • .z.T is the current time in the time datatype; the underlying number in times is milliseconds since midnight, so adding 1000*x gives a time x seconds in the future.

  • -1 string .z.Z prints the current datetime to stdout.

  • while[(.z.T < yr); ..] loops as long as the current time is less than yr (x seconds in the future).

  • ZZ,::.z.Z appends the current datetime to a global variable named ZZ.

some additional notes:

the datetime datatype is in general deprecated in favor of timestamp.

the parentheses around the test condition are redundant.

the second : is also redundant, but for more interesting reasons: ,: (like all of the two-argument "writeback" functions (x+:1, y-:2, etc.)) always modifies either a global or a local variable, depending on whether a local of that name exists in the function.

proof:

q)delete from`.;
q){ZZ:(); yr:.z.T+1000*x; -1 string .z.Z; while[(.z.T < yr); ZZ,::.z.Z]}1
2014.04.30T18:26:24.592
q)ZZ
'ZZ
q)

the ZZ being modified inside the while loop in that version of the function was the local variable declared in the first statement, not a global one as one might assume given the presence of a :: in the modification statement.

anyway, if you want to do it like this, it should at the very least be rewritten to yr:{ yr:.z.T+1000*x; -1 string .z.Z; while[.z.T < yr; ZZ,:.z.Z]}.

Upvotes: 1

Ryan Hamilton
Ryan Hamilton

Reputation: 2615

  • Here :: means assign the value on the right to the global variable on the left
  • ZZ is a global variable
  • ZZ,::.z.Z is shorthand for ZZ::ZZ,.z.Z So it appends the latest time to the global variable ZZ.

e.g.

q)f:{ZZ,::2}
q)f[]
q)ZZ
,2
q)f[]
q)ZZ
2 2

.z.T is the time.

Upvotes: 1

Related Questions