I want to compare multiple threads and processes. I have to send the data which bubble-sorted in different child processes back to parent process then merge data. When data size is <= 10000, it succeeds, but when I input larger data ( 50000, 100000, 500000, max to 1000000):
Data example: 4 152 15 9523 526 1514 2623 ....
(Fisrt number is 4 for now.The others are just random numbers between 0~10000)
Case 3 will get stuck at the line like this:wt1.write... when size is over 50000. If size of data is 500000, even case 1 will be stuck.
Can anybody tell my what's problem in my code ?
This is my code :
def bubble_sort(list)
return list if list.size <= 1
swapped = true
while swapped do
swapped = false
0.upto(list.size-2) do |i|
if list[i] > list[i+1]
list[i], list[i+1] = list[i+1], list[i] # swap the values
swapped = true
end
end
end
return list
end
def mergesort(list)
return list if list.size <= 1
mid = list.size / 2
left = list[0, mid]
right = list[mid, list.size-mid]
merge(mergesort(left), mergesort(right))
end
def merge(left, right)
sorted = []
until left.empty? or right.empty?
if left.first <= right.first
sorted << left.shift # take out left first and push back to sorted
else
sorted << right.shift
end
end
return sorted.concat(left).concat(right)
end
#------------------------------------------------------------------method
#------------------------------------------------------------------main
#print "Input File Name: "
print "Filename is : "
fName = STDIN.gets.chomp() # file name
until File.exist?(fName)
print "Wrong file name! Type again :"
fName = STDIN.gets.chomp()
end
list = File.read(fName).split(' ').map{ |n| n.to_i} # File.read() will return string then split by space.
fName.insert(-5,"_output")
k = list[0].to_i # K is 4 for now
list.delete_at(0) # delete the K
SizeofInput = list.length # get the size of input
copylist = list.clone # copy from list
p = (SizeofInput / k ).to_i # every part size of input
print "Function Number is (1~4, 0 to exit ): "
fNum = STDIN.gets.chomp().to_i
outFile = File.open(fName,'a+') # new an output file n
until fNum === 0
copylist = list.clone
case fNum
when 1 # Case 1-----------------------------------------
puts "#{Time.now}"
start1 = Time.now
bubble_sort(copylist)
stop1 = Time.now
outFile.write(copylist)
outFile.write("\nFunc 1 spend time: #{stop1-start1} seconds Size of input : #{SizeofInput} " + "\n" *5)
puts "Original Time : #{stop1-start1} seconds. Size of input : #{SizeofInput} "
when 2 # Case 2------------------------------------------
sList = Array.new(k) { Array.new()} # sorted list
puts "#{Time.now}"
start2 = Time.now
threads = (0..k-1).map do |i|
if i == k-1
numbers = copylist[i*p..SizeofInput-1].clone# copy the origin array by converting into byte stream
else
numbers = copylist[i*p,p].clone# copy the origin array
end
Thread.new(i) do |i|
bubble_sort(numbers)
sList[i] = numbers.clone
end
end
threads.each{|t| t.join} # => This line will spend lot of time?!
# => main thread waits for child threads
mList = Array.new(k/2) {Array.new()}
thr = (0...k/2).map do |i|
Thread.new(i) do |j|
mList[j] = merge(sList[j*2],sList[(j*2 )+ 1]).clone
end
end
thr.each{|t| t.join}
copylist = merge(mList[0],mList[1]).clone
stop2 = Time.now
outFile.write(copylist)
outFile.write("\nFunc 2 spend time: #{stop2-start2} seconds Size of input : #{SizeofInput} " + "\n" *5)
puts "Spent time: #{stop2 - start2 } seconds. Size of Input : #{copylist.length}"
when 3 # Case 3-------------------------------------------
sList = Array.new(k) { Array.new()}
rd1,wt1 = IO.pipe # reader & writer
rd2,wt2 = IO.pipe
rd3,wt3 = IO.pipe
rd4,wt4 = IO.pipe
rd5,wt5 = IO.pipe
rd6,wt6 = IO.pipe
rd7,wt7 = IO.pipe
puts "#{Time.now}"
start2 = Time.now
pid1 = fork {
puts "1 starts"
rd1.close
numbers = copylist[0,p].clone
bubble_sort(numbers)
sList[0] = numbers.clone
wt1.write sList[0] #Marshal.dump(sList[0])
puts "1 is ok"
Process.exit!(true)
}
pid2 = fork {
puts "2 starts"
rd2.close
numbers = copylist[p,p].clone
bubble_sort(numbers)
sList[1] = numbers.clone
wt2.write sList[1] #Marshal.dump(sList[1])
puts "2 is ok"
Process.exit!(true)
exit
}
pid3 = fork {
puts "3 starts"
rd3.close
numbers = copylist[2*p,p].clone
bubble_sort(numbers)
sList[2] = numbers.clone
wt3.write sList[2] #Marshal.dump(sList[2])
puts "3 is ok"
Process.exit!(true)
}
pid4 = fork {
puts "4 starts"
rd4.close
numbers = copylist[3*p..SizeofInput-1].clone
bubble_sort(numbers)
sList[3] = numbers.clone
wt4.write sList[3] #Marshal.dump(sList[3])
puts "4 is ok"
Process.exit!(true)
}
mList = Array.new(k/2) {Array.new()}
Process.waitpid(pid1)
Process.waitpid(pid2)
wt1.close
wt2.close
puts "Finish Pid1 & 2"
pid5 = fork {
rd5.close
a = ( rd1.read.delete '[]').split(%r{,\s*}).map{ |n| n.to_i} # Marshal.load(rd1.read)
b = ( rd2.read.delete '[]').split(%r{,\s*}).map{ |n| n.to_i} # Marshal.load(rd2.read)
mList[0] = merge(a,b).clone
wt5.write mList[0] #Marshal.dump(mList[0])
Process.exit!(true)
}
Process.waitpid(pid3)
Process.waitpid(pid4)
wt3.close
wt4.close
puts "Finish Pid3 & 4"
pid6 = fork {
rd6.close
a = (rd3.read.delete '[]').split(%r{,\s*}).map{ |n| n.to_i} #Marshal.load(rd3.read)
b = (rd4.read.delete '[]').split(%r{,\s*}).map{ |n| n.to_i} #Marshal.load(rd4.read)
mList[1] = merge(a,b).clone
wt6.write mList[1] #Marshal.dump(mList[1])
Process.exit!(true)
}
Process.waitpid(pid5)
Process.waitpid(pid6)
wt5.close
wt6.close
puts "Finish Pid5 & 6"
pid7 = fork {
rd7.close
a = (rd5.read.delete '[]').split(%r{,\s*}).map{ |n| n.to_i} #Marshal.load(rd5.read)
b = (rd6.read.delete '[]').split(%r{,\s*}).map{ |n| n.to_i} #Marshal.load(rd6.read)
copylist = merge(a,b)
puts "7 is ok"
wt7.write copylist #Marshal.dump(copylist)
Process.exit!(true)
}
Process.waitpid(pid7)
puts "Finish Pid7"
wt7.close
stop2 = Time.now
outFile.write(rd7.read) #Marshal.load(rd7.read))
outFile.write("\nFunc 3 spend time: #{stop2-start2} seconds Size of input : #{SizeofInput} " + "\n" *5)
puts "Spent time: #{stop2 - start2 } seconds. Size of Input : #{copylist.length}"
when 4 # Case 4-------------------------------------------
sList = Array.new(4) { Array.new() } # sort list
start3 = Time.now
(0..3).map do |i|
if i === 3
numbers = copylist[i*p..SizeofInput-1].clone # copy the origin array
else
numbers = copylist[i*p,p].clone
end
sList[i] = bubble_sort(numbers)
end
mList = Array.new(2) { Array.new() } # merge lsit
(0..1).map do |t|
mList[t] = merge(sList[t*2],sList[t*2+1]).clone
end
copylist = merge(mList[0],mList[1]).clone
stop3 = Time.now
outFile.write(copylist)
outFile.write("\nFunc 4 spend time: #{stop3-start3} seconds Size of input : #{SizeofInput} " + "\n" *5)
puts "Spent time: #{stop3 - start3 } seconds. Size of Input : #{copylist.length}"
else puts "Wrong Number!! Try Again!"
end
print "Function Number is (1~4, 0 to exit ): "
fNum = STDIN.gets.chomp().to_i
end # end of until loop
outFile.close()
puts "See you again~"
Related
I have written the logic for the program to perform FizzBuzz operations:
fizzbuzz
module FizzBuzz
class Operation
def input
puts 'Enter a number upto which Fizz/Buzz needs to be printed'
num = gets.chomp.to_i
fizzbuzz_function(num)
end
def fizzbuzz_function(num)
for i in 1..num
if i % 3 == 0 && i % 5 == 0
puts 'FizzBuzz'
elsif i % 3 == 0
puts 'Fizz'
elsif i % 5 == 0
puts 'Buzz'
else
puts i
end
end
end
end
res = Operation.new
res.input
end
But I am trying to print the output in form of a table.
Here is FizzBuzz in form of a table:
def fizzbuzz_gen(num)
Enumerator.new do |y|
(1..num).each do |i|
if i % 3 == 0 && i % 5 == 0
y << 'FizzBuzz'
elsif i % 3 == 0
y << 'Fizz'
elsif i % 5 == 0
y << 'Buzz'
else
y << i.to_s
end
end
end
end
def fill_to_width(width, e)
result = ""
future_length = -1
while result.length + future_length < width
result << e.next
result << " "
future_length = e.peek.length
end
result.center(width)
end
def format_table(num)
fb = fizzbuzz_gen(num)
begin
puts fill_to_width(75, fb)
puts fill_to_width(75, fb)
loop do
puts "%10s%s%31s%s" % ["", fill_to_width(12, fb), "", fill_to_width(12, fb)]
end
rescue StopIteration
end
end
format_table(100)
There may be less numbers output than specified, in order for one leg not to be shorter than another.
def encrypt(string)
alphabet = ("a".."b").to_a
result = ""
idx = 0
while idx < string.length
character = string[idx]
if character == " "
result += " "
else
n = alphabet.index(character)
n_plus = (n + 1) % alphabet.length
result += alphabet[n_plus]
end
idx += 1
end
return result
end
puts encrypt("abc")
puts encrypt("xyz")
I'm trying to get "abc" to print out "bcd" and "xyz" to print "yza". I want to advance the letter forward by 1. Can someone point me to the right direction?
All I had to do was change your alphabet array to go from a to z, not a to b, and it works fine.
def encrypt(string)
alphabet = ("a".."z").to_a
result = ""
idx = 0
while idx < string.length
character = string[idx]
if character == " "
result += " "
else
n = alphabet.index(character)
n_plus = (n + 1) % alphabet.length
result += alphabet[n_plus]
end
idx += 1
end
return result
end
puts encrypt("abc")
puts encrypt("xyz")
Another way to solve the issue, that I think is simpler, personally, is to use String#tr:
ALPHA = ('a'..'z').to_a.join #=> "abcdefghijklmnopqrstuvwxyz"
BMQIB = ('a'..'z').to_a.rotate(1).join #=> "bcdefghijklmnopqrstuvwxyza"
def encrypt(str)
str.tr(ALPHA,BMQIB)
end
def decrypt(str)
str.tr(BMQIB,ALPHA)
end
encrypt('pizza') #=> "qjaab"
decrypt('qjaab') #=> "pizza"
Alternatively if you don't want to take up that memory storing the alphabet you could use character codings and then just use arithmetic operations on them to shift the letters:
def encrypt(string)
result = ""
idx = 0
while idx < string.length
result += (string[idx].ord == 32 ? (string[idx].chr) : (string[idx].ord+1).chr)
idx += 1
end
result
end
Other strange thing about ruby is that you do not need to explicitly return something at the end of the method body. It just returns the last thing by default. This is considered good style amongst ruby folks.
Your question has been answered, so here are a couple of more Ruby-like ways of doing that.
Use String#gsub with a hash
CODE_MAP = ('a'..'z').each_with_object({}) { |c,h| h[c] = c < 'z' ? c.next : 'a' }
#=> {"a"=>"b", "b"=>"c",..., "y"=>"z", "z"=>"a"}
DECODE_MAP = CODE_MAP.invert
#=> {"b"=>"a", "c"=>"b",..., "z"=>"y", "a"=>"z"}
def encrypt(word)
word.gsub(/./, CODE_MAP)
end
def decrypt(word)
word.gsub(/./, DECODE_MAP)
end
encrypt('pizza')
#=> "qjaab"
decrypt('qjaab')
#=> "pizza"
Use String#gsub with Array#rotate
LETTERS = ('a'..'z').to_a
#=> ["a", "b", ..., "z"]
def encrypt(word)
word.gsub(/./) { |c| LETTERS.rotate[LETTERS.index(c)] }
end
def decrypt(word)
word.gsub(/./) { |c| LETTERS.rotate(-1)[LETTERS.index(c)] }
end
encrypt('pizza')
#=> "qjaab"
decrypt('qjaab')
#=> "pizza"
This script is for Project Euler #14
I am refactoring it and all I did was grab 1 line of code n.even? ? n = n/2 : n = (3*n) + 1 and made it into it's own function. This change increase the execution time by 5 seconds.
Why would that happen?
Before:
def longest_collatz_sequence1(count)
check = []
while count >= 1
n = count
seq = [count]
while n > 1
n.even? ? n = n/2 : n = (3*n) + 1
seq << n
end
count -= 1
check << seq
value = sequence_check(check) if check.length == 2
end
puts "The number that produces the largest chain is: #{value[0][0]}"
end
def sequence_check(check)
check[0].length > check[1].length ? check.delete_at(1) : check.delete_at(0)
check
end
s = Time.new
longest_collatz_sequence1 1000000
puts "elapsed: #{Time.new-s}"
#~12.2 seconds
After:
def longest_collatz_sequence1(count)
check = []
while count >= 1
n = count
seq = [count]
while n > 1
n=collatz(n)
seq << n
end
count -= 1
check << seq
value = sequence_check(check) if check.length == 2
end
puts "The number that produces the largest chain is: #{value[0][0]}"
end
def collatz(n)
n.even? ? n = n/2 : n = (3*n) + 1
end
def sequence_check(check)
check[0].length > check[1].length ? check.delete_at(1) : check.delete_at(0)
check
end
s = Time.new
longest_collatz_sequence1 1000000
puts "elapsed: #{Time.new-s}"
#~17.7 seconds
I'm asked to write the ruby program that generate the output based the given command,
The full description
I'm really new in ruby (maybe few hours that I have started ruby)
I'm getting this error, please check my code for other possible errors:
Thank you.
n `block in each2': undefined method `[]' for #<MyVector:0x00000002c4ad90 #array=[2, 3, 4]> (NoMethodError)
What I have done so far:
# MyVector Class
class MyVector
def initialize (a)
if !(a.instance_of? Array)
raise "ARGUMENT OF INITIALIZER MUST BE AN ARRAY"
else
#array = a
end
end
def array
#array
end
def to_s
#array.to_s
end
def length
#array.length
end
def each2(a)
raise Error, "INTEGER IS NOT LIKE VECTOR" if a.kind_of?(Integer)
Vector.Raise Error if length != a.length
return to_enum(:each2, a) unless block_given?
length.times do |i|
yield #array[i], a[i]
end
self
end
def * (a)
Vector.Raise Error if length != a.length
p = 0
each2(a) {|a1, a2|p += a1 * a2}
p
end
end
# MyMatrix Class
class MyMatrix
def initialize a
#array=Array.new(a.length)
i=0
while(i<a.length)
#array[i]=MyVector.new(a[i])
end
end
def to_s
#array.to_s
end
def transpose
size=vectors[0].length
arr= Array.new(size)
i=0
while i<size
a=Array.new(vector.length)
j=0
while j<a.length
a[j]=vectors[j].arr[i]
j+=1
end
arr[i]=a
i+=1
end
arr[i]=a
i+=1
end
def *m
if !(m instance_of? MyMatrix)
raise Error
a=Array.new(#array.length)
i=0
while (i<#array.length)
a[i]=#array[i]*m
i=i+1
end
end
end
end
Input:
Test code
v = MyVector.new([1,2,3])
puts "v = " + v.to_s
v1 = MyVector.new([2,3,4])
puts "v1 = " + v1.to_s
puts "v * v1 = " + (v * v1).to_s
m = MyMatrix.new([[1,2], [1, 2], [1, 2]])
puts "m = " + m.to_s + "\n"
puts "v * m = " + (v * m).to_s
m1 = MyMatrix.new([[1, 2, 3], [2, 3, 4]])
puts "m1 = " + m1.to_s + "\n"
puts "m * m1 = " + (m * m1).to_s
puts "m1 * m = " + (m1 * m).to_s
Desired Output:
v = 1 2 3
v1 = 2 3 4
v * v1 = 20
m =
1 2
1 2
1 2
v * m = 6 12
m1 =
1 2 3
2 3 4
m * m1 =
5 8 11
5 8 11
5 8 11
m1 * m =
6 12
9 18
length.times do |i|
yield #array[i], a[i]
end
In the above block, a is an instance of MyVector. You need to define the [] operator on it, probably something like:
def [](i)
#array[i]
end
I have:
a = "This is Product A with property B and propery C. Buy it now!"
b = "This is Product B with property X and propery Y. Buy it now!"
c = "This is Product C having no properties. Buy it now!"
I'm looking for an algorithm that can do:
> magic(a, b, c)
=> ['A with property B and propery C',
'B with property X and propery Y',
'C having no properties']
I have to find for duplicates in 1000+ texts. Super performance isn't a must, but would be nice.
-- Update
I'm looking for sequence of words. So if:
d = 'This is Product D with text engraving: "Buy". Buy it now!'
The first "Buy" should not be a duplicate. I'm guessing I have to use a threshold of n words following eachother in order to be seen as duplicate.
def common_prefix_length(*args)
first = args.shift
(0..first.size).find_index { |i| args.any? { |a| a[i] != first[i] } }
end
def magic(*args)
i = common_prefix_length(*args)
args = args.map { |a| a[i..-1].reverse }
i = common_prefix_length(*args)
args.map { |a| a[i..-1].reverse }
end
a = "This is Product A with property B and propery C. Buy it now!"
b = "This is Product B with property X and propery Y. Buy it now!"
c = "This is Product C having no properties. Buy it now!"
magic(a,b,c)
# => ["A with property B and propery C",
# "B with property X and propery Y",
# "C having no properties"]
Your data
sentences = [
"This is Product A with property B and propery C. Buy it now!",
"This is Product B with property X and propery Y. Buy it now!",
"This is Product C having no properties. Buy it now!"
]
Your magic
def magic(data)
prefix, postfix = 0, -1
data.map{ |d| d[prefix] }.uniq.compact.size == 1 && prefix += 1 or break while true
data.map{ |d| d[postfix] }.uniq.compact.size == 1 && prefix > -postfix && postfix -= 1 or break while true
data.map{ |d| d[prefix..postfix] }
end
Your output
magic(sentences)
#=> [
#=> "A with property B and propery C",
#=> "B with property X and propery Y",
#=> "C having no properties"
#=> ]
Or you can use loop instead of while true
def magic(data)
prefix, postfix = 0, -1
loop{ data.map{ |d| d[prefix] }.uniq.compact.size == 1 && prefix += 1 or break }
loop{ data.map{ |d| d[postfix] }.uniq.compact.size == 1 && prefix > -postfix && postfix -= 1 or break }
data.map{ |d| d[prefix..postfix] }
end
edit: this code has bugs. Just leaving my answer for reference and because i dont like it if people delete answers after being downvoted. Everyone makes mistakes :-)
I liked #falsetru's approach but felt the code was unnecessarily complex. Here's my attempt:
def common_prefix_length(strings)
i = 0
i += 1 while strings.map{|s| s[i] }.uniq.size == 1
i
end
def common_suffix_length(strings)
common_prefix_length(strings.map(&:reverse))
end
def uncommon_infixes(strings)
pl = common_prefix_length(strings)
sl = common_suffix_length(strings)
strings.map{|s| s[pl...-sl] }
end
As the OP may be concerned about performance, i did a quick benchmark:
require 'fruity'
require 'securerandom'
prefix = 'PREFIX '
suffix = ' SUFFIX'
test_data = Array.new(1000) do
prefix + SecureRandom.hex + suffix
end
def fl00r_meth(data)
prefix, postfix = 0, -1
data.map{ |d| d[prefix] }.uniq.size == 1 && prefix += 1 or break while true
data.map{ |d| d[postfix] }.uniq.size == 1 && postfix -= 1 or break while true
data.map{ |d| d[prefix..postfix] }
end
def falsetru_common_prefix_length(*args)
first = args.shift
(0..first.size).find_index { |i| args.any? { |a| a[i] != first[i] } }
end
def falsetru_meth(*args)
i = falsetru_common_prefix_length(*args)
args = args.map { |a| a[i..-1].reverse }
i = falsetru_common_prefix_length(*args)
args.map { |a| a[i..-1].reverse }
end
def padde_common_prefix_length(strings)
i = 0
i += 1 while strings.map{|s| s[i] }.uniq.size == 1
i
end
def padde_common_suffix_length(strings)
padde_common_prefix_length(strings.map(&:reverse))
end
def padde_meth(strings)
pl = padde_common_prefix_length(strings)
sl = padde_common_suffix_length(strings)
strings.map{|s| s[pl...-sl] }
end
compare do
fl00r do
fl00r_meth(test_data.dup)
end
falsetru do
falsetru_meth(*test_data.dup)
end
padde do
padde_meth(test_data.dup)
end
end
These are the results:
Running each test once. Test will take about 1 second.
fl00r is similar to padde
padde is faster than falsetru by 30.000000000000004% ± 10.0%