ruby chaining commands inline for a TCL programmer - ruby

I am a TCL programmer and do a lot of statement chaining and don't know how that can be done in ruby
For example if i would want to append the current time to the value of a variable
for example in tcl:
set mylist [list a b c,d,e f]
set myelem_with_time "[lindex [split [lindex $mylist 2] ,] 0][clock seconds]"
>>c{with some time value}
How can this be achieved in ruby without using separate lines for each command
(of course its not an object class method or else use . operator, for example chaining the current time, or some arithmetic operation etc)
psudo code:
myval = mylist[2].split(",")[0] + time()+60seconds;
(I want to interpolate the time + 60 without calculating on a previous line)

mylist = %w[a b c,d,e f]
myelem_with_time = mylist[2].split(',')[0] + (Time.now + 60).to_i.to_s
# or
myelem_with_time = "%s%d" % [mylist[2].split(',')[0], (Time.now + 60).to_i]
# or
myelem_with_time = "#{mylist[2].split(',')[0]}#{(Time.now + 60).to_i}"

Using your list from above and playing with your command:
mylist[2].split(",")[0] + (Time.now + 60).to_s
I got:
e f2012-02-28 04:46:55 -0700
Is that what you're looking for (I did not strip the Date from the output but that is possible)

Related

Redis Sorted Set: Bulk ZSCORE

How to get a list of members based on their ID from a sorted set instead of just one member?
I would like to build a subset with a set of IDs from the actual sorted set.
I am using a Ruby client for Redis and do not want to iterate one by one. Because there could more than 3000 members that I want to lookup.
Here is the issue tracker to a new command ZMSCORE to do bulk ZSCORE.
There is no variadic form for ZSCORE, yet - see the discussion at: https://github.com/antirez/redis/issues/2344
That said, and for the time being, what you could do is use a Lua script for that. For example:
local scores = {}
while #ARGV > 0 do
scores[#scores+1] = redis.call('ZSCORE', KEYS[1], table.remove(ARGV, 1))
end
return scores
Running this from the command line would look like:
$ redis-cli ZADD foo 1 a 2 b 3 c 4 d
(integer) 4
$ redis-cli --eval mzscore.lua foo , b d
1) "2"
2) "4"
EDIT: In Ruby, it would probably be something like the following, although you'd be better off using SCRIPT LOAD and EVALSHA and loading the script from an external file (instead of hardcoding it in the app):
require 'redis'
script = <<LUA
local scores = {}
while #ARGV > 0 do
scores[#scores+1] = redis.call('ZSCORE', KEYS[1], table.remove(ARGV, 1))
end
return scores
LUA
redis = ::Redis.new()
reply = redis.eval(script, ["foo"], ["b", "d"])
Lua script to get scores with member IDs:
local scores = {}
while #ARGV > 0 do
local member_id = table.remove(ARGV, 1)
local member_score = {}
member_score[1] = member_id
member_score[2] = redis.call('ZSCORE', KEYS[1], member_id)
scores[#scores + 1] = member_score
end
return scores

Ruby - How to subtract numbers of two files and save the result in one of them on a specified position?

I have 2 txt files with different strings and numbers in them splitted with ;
Now I need to subtract the
((number on position 2 in file1) - (number on position 25 in file2)) = result
Now I want to replace the (number on position 2 in file1) with the result.
I tried my code below but it only appends the number in the end of the file and its not the result of the calculation which got appended.
def calc
f1 = File.open("./file1.txt", File::RDWR)
f2 = File.open("./file2.txt", File::RDWR)
f1.flock(File::LOCK_EX)
f2.flock(File::LOCK_EX)
f1.each.zip(f2.each).each do |line, line2|
bg = line.split(";").compact.collect(&:strip)
bd = line2.split(";").compact.collect(&:strip)
n = bd[2].to_i - bg[25].to_i
f2.print bd[2] << n
#puts "#{n}" Only for testing
end
f1.flock(File::LOCK_UN)
f2.flock(File::LOCK_UN)
f1.close && f2.close
end
Use something like this:
lines1 = File.readlines('file1.txt').map(&:to_i)
lines2 = File.readlines('file2.txt').map(&:to_i)
result = lines1.zip(lines2).map do |value1, value2| value1 - value2 }
File.write('file1.txt', result.join(?\n))
This code load all files in memory, then calculate result and write it to first file.
FYI: If you want to use your code just save result to other file (i.e. result.txt) and at the end copy it to original file.

Multiprocessing and shared multiprocessing manager lists for parsing large file

I am trying to parse a huge file (approx 23 MB) using the code below, wherein I populate a multiprocessing.manager.list with all the lines read from the file . In the target routine (parse_line) for each process, I pop a line and parse it to create a defaultdict object with certain parsed attributes and finally push each of these objects into another multiprocessing.manager.list.
class parser(object):
def __init__(self):
self.manager = mp.Manager()
self.in_list = self.manager.list()
self.out_list = self.manager.list()
self.dict_list,self.lines, self.pcap_text = [],[],[]
self.last_timestamp = [[(999999,0)]*32]*2
self.num = Word(nums)
self.word = Word(alphas)
self.open_brace = Suppress(Literal("["))
self.close_brace = Suppress(Literal("]"))
self.colon = Literal(":")
self.stime = Combine(OneOrMore(self.num + self.colon) + self.num + Literal(".") + self.num)
self.date = OneOrMore(self.word) + self.num + self.stime
self.is_cavium = self.open_brace + (Suppress(self.word)) + self.close_brace
self.oct_id = self.open_brace + Suppress(self.word) + Suppress(Literal("=")) \
+ self.num + self.close_brace
self.core_id = self.open_brace + Suppress(self.word) + Suppress(Literal("#")) \
+ self.num + self.close_brace
self.ppm_id = self.open_brace + self.num + self.close_brace
self.oct_ts = self.open_brace + self.num + self.close_brace
self.dump = Suppress(Word(hexnums) + Literal(":")) + OneOrMore(Word(hexnums))
self.opening = Suppress(self.date) + Optional(self.is_cavium.setResultsName("cavium")) \
+ self.oct_id.setResultsName("octeon").setParseAction(lambda toks:int(toks[0])) \
+ self.core_id.setResultsName("core").setParseAction(lambda toks:int(toks[0])) \
+ Optional(self.ppm_id.setResultsName("ppm").setParseAction(lambda toks:int(toks[0])) \
+ self.oct_ts.setResultsName("timestamp").setParseAction(lambda toks:int(toks[0]))) \
+ Optional(self.dump.setResultsName("pcap"))
def parse_file(self, filepath):
self.filepath = filepath
with open(self.filepath,'r') as f:
self.lines = f.readlines()
for lineno,line in enumerate(self.lines):
self.in_list.append((lineno,line))
processes = [mp.Process(target=self.parse_line) for i in range(mp.cpu_count())]
[process.start() for process in processes]
[process.join() for process in processes]
while self.in_list:
(lineno, len) = self.in_list.pop()
print mp.current_process().name, "start"
dic = defaultdict(int)
result = self.opening.parseString(line)
self.pcap_text.append("".join(result.pcap))
if result.timestamp or result.ppm:
dic['oct'], dic['core'], dic['ppm'], dic['timestamp'] = result[0:4]
self.last_timestamp[result.octeon][result.core] = (result.ppm,result.timestamp)
else:
dic['oct'], dic['core'] = result[0:2]
dic['ppm'] = (self.last_timestamp[result.octeon][result.core])[0]
dic['ts'] = (self.last_timestamp[result.octeon][result.core])[1]
dic['line'] = lineno
self.out_list.append(dic)
However this entire process takes approximately 3 minutes to complete.
My question is, if there is a better way to make this faster ?
I am using pyparsing module to parse each line, if it makes any difference.
PS: Made changes in the routine Paul McGuire's advice
Not a big performance issue, but learn to iterate over files directly, instead of using readlines(). In place of this code:
self.lines = f.readlines()
for lineno,line in enumerate(self.lines):
self.in_list.append((lineno,line))
You can write:
self.in_list = list(enumerate(f))
A hidden performance killer is using while self.in_list: (lineno,line) = list.pop(). Each call to pop removes the 0'th element from the list. Unfortunately, Python's lists are implemented as arrays. To remove the 0'th element, the 1..n-1'th elements have to be moved up one slot in the array. You don't really have to destroy self.in_list as you go, just iterate over it:
for lineno, line in self.in_list:
<Do something with line and line no. Parse each line and push into out_list>
If you are thinking that consuming self.in_list as you go is a memory-saving measure, then you can avoid the array-shifting inefficiency of Python lists by using a deque instead (from Python's provided collections module). deque's are implemented internally as linked lists, so that pushing or popping to and from either end is very fast, but indexed access is slow. To use a deque, replace the line:
self.in_list = list(enumerate(f))
with:
self.in_list = deque(enumerate(f))
Then replace the call in your code self.in_list.pop() with self.in_list.popleft().
But MUCH more likely to be the performance issue is the pyparsing code you are using to process each line. But since you didn't post the parser code, there is not much help we can provide there.
To get an idea about where the time is going, try leaving all your code, and then comment out the <Do something with line and line no. Parse each line and push into out_list> code (you may have to add a pass statement for the for loop), and then run against your 23MB file. This will give you a rough idea about how much of your 3 minutes is being spent in reading and iterating over the file, and how much is being spent doing the actual parsing. Then post back in another question when you find where the real performance issues lie.

Calculating the difference between durations with milliseconds in Ruby

TL;DR: I need to get the difference between HH:MM:SS.ms and HH:MM:SS.ms as HH:MM:SS:ms
What I need:
Here's a tricky one. I'm trying to calculate the difference between two timestamps such as the following:
In: 00:00:10.520
Out: 00:00:23.720
Should deliver:
Diff: 00:00:13.200
I thought I'd parse the times into actual Time objects and use the difference there. This works great in the previous case, and returns 00:0:13.200.
What doesn't work:
However, for some, this doesn't work right, as Ruby uses usec instead of msec:
In: 00:2:22.760
Out: 00:2:31.520
Diff: 00:0:8.999760
Obviously, the difference should be 00:00:8:760 and not 00:00:8.999760. I'm really tempted to just tdiff.usec.to_s.gsub('999','') ……
My code so far:
Here's my code so far (these are parsed from the input strings like "0:00:10:520").
tin_first, tin_second = ins.split(".")
tin_hours, tin_minutes, tin_seconds = tin_first.split(":")
tin_usec = tin_second * 1000
tin = Time.gm(0, 1, 1, tin_hours, tin_minutes, tin_seconds, tin_usec)
The same happens for tout. Then:
tdiff = Time.at(tout-tin)
For the output, I use:
"00:#{tdiff.min}:#{tdiff.sec}.#{tdiff.usec}"
Is there any faster way to do this? Remember, I just want to have the difference between two times. What am I missing?
I'm using Ruby 1.9.3p6 at the moment.
Using Time:
require 'time' # Needed for Time.parse
def time_diff(time1_str, time2_str)
t = Time.at( Time.parse(time2_str) - Time.parse(time1_str) )
(t - t.gmt_offset).strftime("%H:%M:%S.%L")
end
out_time = "00:00:24.240"
in_time = "00:00:14.520"
p time_diff(in_time, out_time)
#=> "00:00:09.720"
Here's a solution that doesn't rely on Time:
def slhck_diff( t1, t2 )
ms_to_time( time_as_ms(t2) - time_as_ms(t1) )
end
# Converts "00:2:22.760" to 142760
def time_as_ms( time_str )
re = /(\d+):(\d+):(\d+)(?:\.(\d+))?/
parts = time_str.match(re).to_a.map(&:to_i)
parts[4]+(parts[3]+(parts[2]+parts[1]*60)*60)*1000
end
# Converts 142760 to "00:02:22.760"
def ms_to_time(ms)
m = ms.floor / 60000
"%02i:%02i:%06.3f" % [ m/60, m%60, ms/1000.0 % 60 ]
end
t1 = "00:00:10.520"
t2 = "01:00:23.720"
p slhck_diff(t1,t2)
#=> "01:00:13.200"
t1 = "00:2:22.760"
t2 = "00:2:31.520"
p slhck_diff(t1,t2)
#=> "00:00:08.760"
I figured the following could work:
out_time = "00:00:24.240"
in_time = "00:00:14.520"
diff = Time.parse(out_time) - Time.parse(in_time)
Time.at(diff).strftime("%H:%M:%S.%L")
# => "01:00:09.720"
It does print 01 for the hour, which I don't really understand.
In the meantime, I used:
Time.at(diff).strftime("00:%M:%S.%L")
# => "00:00:09.720"
Any answer that does this better will get an upvote or the accept, of course.
in_time = "00:02:22.760"
out_time = "00:02:31.520"
diff = (Time.parse(out_time) - Time.parse(in_time))*1000
puts diff
OUTPUT:
8760.0 millliseconds
Time.parse(out_time) - Time.parse(in_time) gives the result in seconds so multiplied by 1000 to convert into milliseconds.

Date-time comparison in Ruby

I have one date, let's say '2010-12-20' of a flight departure, and two times, for instance, '23:30' and '02:15'.
The problem: I need to get datetimes (yyyy-MM-dd HH:mm:ss, for example, 2010-12-17 14:38:32) of both of these dates, but I don't know the day of the second time (it can be the same day as departure, or the next one).
I am looking for the best solution in Ruby on Rails. In PHP would just use string splitting multiple times, but I believe, that Rails as usually, has a much more elegant way.
So, here is my pseudo code, which I want to turn into Ruby:
depart_time = '23:30'
arrive_time = '02:15'
depart_date = '2010-12-20'
arrive_date = (arrive.hour < depart.hour and arrive.hour < 5) ? depart_date + 1 : depart_date
# Final results
depart = depart_date + ' ' + depart_time
arrive = arrive_date + ' ' + arrive_time
I want to find the best way to implement this in Ruby on Rails, instead of just playing with strings.
This is just pure Ruby, nothing to do with Rails:
require 'date'
depart_time = DateTime.strptime '23:30', '%H:%M'
arrive_time = DateTime.strptime '02:15', '%H:%M'
arrive_date = depart_date = Date.parse( '2010-12-20' )
arrive_date += 1 if arrive_time.hour < depart_time.hour and arrive_time.hour < 5
puts "#{depart_date} #{depart_time.strftime '%H:%M'}",
"#{arrive_date} #{arrive_time.strftime '%H:%M'}"
#=> 2010-12-20 23:30
#=> 2010-12-21 02:15

Resources