I am creating threads in a for loop, and I want to use the for loop's i as the name for each particular thread. When I run this, instead of getting 1,2 or 2,1, I am getting 2,2. Is there a better/safer way to pass variables into a thread?
ts = []
for i in 1..2 do
ts.push( Thread.new(i) do
x = i
puts x
end)
end
ts.each do |t|
t.join()
end
Your problem is that the i you are referring to is not a block variable passed to the thread but is the i defined outside of the thread. You need to add |i| to it, and you will get either 1, 2 or 2, 1.
ts = []
for i in 1..2 do
ts.push( Thread.new(i) do |i|
x = i
puts x
end)
end
ts.each do |t|
t.join()
end
By the way, a more rubyish way to write is:
ts = (1..2).map do |i|
Thread.new(i) do |i|
puts i
end
end.each(&:join)
If you are looking for a unique name for each thread, I suggest using the object id of the thread.
ts = (1..2).map do
Thread.new do
puts Thread.current.object_id
end
end.each(&:join)
You can pass variable through the block
ts = []
for i in 1..2 do
ts.push( Thread.new(i) do |i|
x = i
puts x
end)
end
ts.each do |t|
t.join()
end
# => 1
# => 2
Related
I am running multiple threads, and when one of the threads sets the global function '$trade_executed' to true I want it to kill all other threads and remove them from the global '$threads' array.
Then I restart the thread creation process.
Below is a simplified version of my codebase.
3 Threads are created and it looks like 2 threads are deleted but a third thread stays. (for reasons unknown)
Ideally this script would never print '2' or '3' because it would always trigger at '1' minute and kill all threads and reset.
*
thr.exit is preferred. I don't want any code pushed from other threads with a thr.join after $trade_executed is set
require 'thread'
class Finnean
def initialize
#lock = Mutex.new
end
def digger(minute)
sleep(minute * 60)
coco(minute)
end
def coco(minute)
#lock.synchronize {
puts "coco #{minute}"
$threads.each do |thr|
next if thr == Thread.current
thr.exit
end
$trade_executed = true
Thread.current.exit
}
end
end
minutes = [1, 2, 3]
$threads = Array.new
$trade_executed = false
abc = Finnean.new
def start_threads(minutes, abc)
minutes.each do |minute|
$threads << Thread.new {abc.digger(minute)}
puts minute
end
end
start_threads(minutes, abc)
while true
if $trade_executed != false then
count = 0
$threads.map! do |thr|
count += 1
puts "#{thr} & #{thr.status}"
thr.exit
$threads.delete(thr)
puts "Iteration #{count}"
end
count = 0
$threads.each do |thr|
count += 1
puts "#{thr}" ##{thr.status}
puts "Threads Still Left: #{count}"
end
$trade_executed = false
abc = Finnean.new
start_threads(minutes, abc)
end
end
Why not make a thread killer that you keep locked up until the first one finishes:
# Create two variables that can be passed in to the Thread.new block closure
threads = [ ]
killer = nil
# Create 10 threads, each of which waits a random amount of time before waking up the thread killer
10.times do |n|
threads << Thread.new do
sleep(rand(2..25))
puts "Thread #{n} finished!"
killer.wakeup
end
end
# Define a thread killer that will call `kill` on all threads, then `join`
killer = Thread.new(threads) do
Thread.stop
threads.each do |thread|
puts "Killing #{thread}"
thread.kill
thread.join
end
end
# The killer will run last, so wait for that to finish
killer.join
You can't force a thread to exit, but you can kill it. That generates an exception you could rescue and deal with as necessary.
I want to pass a block to a function, and then call that block with some additional parameters as follows:
def foo(&block)
some_array = (1..3).to_a
x = 7 # Simplified
result = some_array.map &block # Need some way to pass in 'x' here
end
def a_usage_that_works
foo do |value|
value
end
end
def a_usage_that_doesnt_work
foo do |value, x|
x # How do I pass in x?
end
end
# rspec to demonstrate problem / required result
describe "spike" do
it "works" do
a_usage_that_works.should == [1,2,3]
end
it "doesn't work" do
a_usage_that_doesnt_work.should == [7, 7, 7]
end
end
How can I pass in the additional parameter to the block?
Create another block and call first one from it.
def foo(&block)
some_array = (1..3).to_a
x = 7 # Simplified
result = some_array.map {|elem| block.call(elem, x)}
end
You pass to the block by yielding to it.
def foo(&block)
some_array = [1,2,3]
x = 7
some_array.map{|el| yield el, x}
end
p foo{|p1, p2| p2} #=>[7,7,7]
p foo{|p1, p2| p1} #=>[1,2,3]
You can use a higher-order function to generate a simplified function:
Let's assume that the block we pass to foo will accept value, x.
Naive strategy, using an inline-defined x:
def foo(&block)
some_array = (1..3).to_a
x = 7
simple_func = proc {|value| block.call(value, x) }
result = some_array.map &simple_func
end
Strategy using separation of concerns:
def get_simple_func(block)
# This assumes x won't change per iteration.
# If it can change, you can move the calculation inside the proc.
# Moving it inside also allows the calculation to depend on "value", in case you want that.
x = complex_calculation_for_x()
proc {|value| block.call(value, x) }
end
def foo(&block)
some_array = (1..3).to_a
simple_func = get_simple_func(block)
result = some_array.map &simple_func
end
Obviously you shouldn't use this when x is a literal value because it would be over-engineering. But as the calculation of x becomes more complex, separating it out makes the code more readable. Also, foo can focus on the specific task of applying the function to some_array.
When writing iterative code with mutation in ruby, I often find myself following this pattern:
def build_x some_data
x = [] # or x = {}
some_data.each do |data|
x.some_in_place_update! (... data ...)
end
x
end
(x often does not have the same shape as some_data, so a simple map will not do.)
Is there a more idiomatic or better way to write code that follows this pattern?
[edit] A real example:
def to_hierarchy stuff
h = {}
stuff.each do |thing|
path = thing.uri.split("/").drop(4)
sub_h = h
path.each do |segment|
sub_h[segment] ||= {}
sub_h = sub_h[segment]
end
sub_h.merge!(
data: thing.data,
)
end
h
end
This begins with a flat list of things, which have related but distinct uris. It transforms this flat list into a hierarchy, grouping related things that share the same segments of a uri. This follows the pattern I described: initialize h, loop over some data and mutate h along the way, and then spit out h at the end.
[edit2] Another related example
def count_data obj
i = if obj[:data] then 1 else 0
obj.each do |k, v|
i += count_statements v unless :data == k
end
i
end
Your to_hierarchy example could be done with each_with_object:
def to_hierarchy stuff
stuff.each_with_object({}) do |thing, h|
#...
end
end
each_with_object passes the extra object to the block and returns that object when the iteration is done.
If you're more of a traditionalist, you could use inject:
def to_hierarchy stuff
stuff.inject({}) do |h, thing|
#...
h
end
end
Note the block argument order change and that the block has to return h so that inject can feed it back into the next block invocation.
Your general example could be written as:
def build_x some_data
some_data.each_with_object([]) do |data, x|
x.some_in_place_update! (... data ...)
end
end
or:
def build_x some_data
some_data.inject({}) do |x, data|
x.some_in_place_update! (... data ...)
x
end
end
Ah! You want each_with_object. Like this
def to_hierarchy stuff
stuff.each_with_object({}) do |thing, h|
path = thing.uri.split("/").drop(4)
sub_h = h
path.each do |segment|
sub_h[segment] ||= {}
sub_h = sub_h[segment]
end
sub_h.merge!(
data: thing.data,
)
end
end
For example, the words "stack", I want to get an array like:
['s', 'st', 'sta', ... 'stack', 't', 'ta', ... , 'c', 'ck', 'k']
I did this by such code:
def split_word(str)
result = []
chas = str.split("")
len = chas.size
(0..len-1).each do |i|
(i..len-1).each do |j|
result.push(chas[i..j].join)
end
end
result.uniq
end
Is there better and clean way to do that? Thanks.
def split_word s
(0..s.length).inject([]){|ai,i|
(1..s.length - i).inject(ai){|aj,j|
aj << s[i,j]
}
}.uniq
end
And you can also consider using Set instead of Array for the result.
PS: Here's another idea, based on array product:
def split_word s
indices = (0...s.length).to_a
indices.product(indices).reject{|i,j| i > j}.map{|i,j| s[i..j]}.uniq
end
I'd write:
def split_word(s)
0.upto(s.length - 1).flat_map do |start|
1.upto(s.length - start).map do |length|
s[start, length]
end
end.uniq
end
groups = split_word("stack")
# ["s", "st", "sta", "stac", "stack", "t", "ta", "tac", "tack", "a", "ac", "ack", "c", "ck", "k"]
It's usually more clear and more compact to use map (functional) instead of the pattern init empty + each + append + return (imperative).
def substrings(str)
output = []
(0...str.length).each do |i|
(i...str.length).each do |j|
output << str[i..j]
end
end
output
end
this is just a cleaned up version of your method and it works with less steps =)
Don't think so.
Here's my attempted version:
def split_word(str)
length = str.length - 1
[].tap do |result|
0.upto(length) do |i|
length.downto(i) do |j|
substring = str[i..j]
result << substring unless result.include?(substring)
end
end
end
end
def substrings(str)
(0...str.length).map do |i|
(i...str.length).each { |j| str[i..j]}
end
end
Just another way to do it, that reads a little clearer to me.
Here is the recursive way to get all the possible sub strings.
def substrings str
return [] if str.size < 1
((0..str.size-1).map do |pos|
str[0..pos]
end) + substrings(str[1..])
end
Way later, but this is what I got from reformatting your code a bit.
def substrings(string)
siz = string.length
answer = []
(0..siz-1).each do |n|
(n..siz-1).each do |i|
answer << string[n..i]
end
end
answer
end
I need a chunk of Ruby code to combine an array of contents like such:
[{:dim_location=>[{:dim_city=>:dim_state}]},
:dim_marital_status,
{:dim_location=>[:dim_zip, :dim_business]}]
into:
[{:dim_location => [:dim_business, {:dim_city=>:dim_state}, :dim_zip]},
:dim_marital_status]
It needs to support an arbitrary level of depth, though the depth will rarely be beyond 8 levels deep.
Revised after comment:
source = [{:dim_location=>[{:dim_city=>:dim_state}]}, :dim_marital_status, {:dim_location=>[:dim_zip, :dim_business]}]
expected = [{:dim_location => [:dim_business, {:dim_city=>:dim_state}, :dim_zip]}, :dim_marital_status]
source2 = [{:dim_location=>{:dim_city=>:dim_state}}, {:dim_location=>:dim_city}]
def merge_dim_locations(array)
return array unless array.is_a?(Array)
values = array.dup
dim_locations = values.select {|x| x.is_a?(Hash) && x.has_key?(:dim_location)}
old_index = values.index(dim_locations[0]) unless dim_locations.empty?
merged = dim_locations.inject({}) do |memo, obj|
values.delete(obj)
x = merge_dim_locations(obj[:dim_location])
if x.is_a?(Array)
memo[:dim_location] = (memo[:dim_location] || []) + x
else
memo[:dim_location] ||= []
memo[:dim_location] << x
end
memo
end
unless merged.empty?
values.insert(old_index, merged)
end
values
end
puts "source1:"
puts source.inspect
puts "result1:"
puts merge_dim_locations(source).inspect
puts "expected1:"
puts expected.inspect
puts "\nsource2:"
puts source2.inspect
puts "result2:"
puts merge_dim_locations(source2).inspect
I don't think there's enough detail in your question to give you a complete answer, but this might get you started:
class Hash
def recursive_merge!(other)
other.keys.each do |k|
if self[k].is_a?(Array) && other[k].is_a?(Array)
self[k] += other[k]
elsif self[k].is_a?(Hash) && other[k].is_a?(Hash)
self[k].recursive_merge!(other[k])
else
self[k] = other[k]
end
end
self
end
end