Script on hash sort - is it possible to optimize?

I wrote a ruby script hash sort related, but feel it’s not good, is it
possible to optimize?

==========================================
There is a string(“string_sample”, every line end with “\n”),
I want the strings sort by user names with the licenses number used.(If
line without license number, then license number=1)
example: User name1 use 1(string_sample line1) + 2(string_sample line4)
, total 3 licenses

string_sample = " name1 machin1 NoXDisplay (v2012.12) (server1/port1
18709), start Fri 1/24 17:26
name2 mchine2 NoXDisplay J3_ffffffffa8c0a600_21848_2 (v2012.12)
(server2/port2 13335), start Fri 1/24 9:29
name2 machine3 NoXDisplay J3_ffffffffa8c0a600_21848_1 (v2012.12)
(server3/port3 8569), start Fri 1/24 9:26
name1 machine4 NoXDisplay (v2012.12) (192.168.0.197/27007 38446),
start Fri 1/24 19:07, 2 licenses
name3 machine5 NoXDisplay (v2012.12) (server4/port4 10195), start
Wed 1/22 10:30
name3 machine6 NoXDisplay J3_ffffffffa8c0a600_21848_3 (v2012.12)
(server5/port5 6975), start Fri 1/24 9:30
name6 machine7 NoXDisplay (v2012.12) (server6/port6 16114), start
Thu 1/23 15:31"

=>

==================
name1(3)

name1 machin1 NoXDisplay (v2012.12) (server1/port1 18709), start Fri

1/24 17:26
name1 machine4 NoXDisplay (v2012.12) (192.168.0.197/27007 38446),
start Fri 1/24 19:07, 2 licenses

name3(2)

name3 machine5 NoXDisplay (v2012.12) (server4/port4 10195), start

Wed 1/22 10:30
name3 machine6 NoXDisplay J3_ffffffffa8c0a600_21848_3 (v2012.12)
(server5/port5 6975), start Fri 1/24 9:30

name2(2)

name2 mchine2 NoXDisplay J3_ffffffffa8c0a600_21848_2 (v2012.12)

(server2/port2 13335), start Fri 1/24 9:29
name2 machine3 NoXDisplay J3_ffffffffa8c0a600_21848_1 (v2012.12)
(server3/port3 8569), start Fri 1/24 9:26

name6(1)

name6 machine7 NoXDisplay (v2012.12) (server6/port6 16114), start

Thu 1/23 15:31

#==========================================
#test.rb
#==========================================
string_sample = " name1 machin1 NoXDisplay (v2012.12) (server1/port1
18709), start Fri 1/24 17:26
name2 mchine2 NoXDisplay J3_ffffffffa8c0a600_21848_2 (v2012.12)
(server2/port2 13335), start Fri 1/24 9:29
name2 machine3 NoXDisplay J3_ffffffffa8c0a600_21848_1 (v2012.12)
(server3/port3 8569), start Fri 1/24 9:26
name1 machine4 NoXDisplay (v2012.12) (192.168.0.197/27007 38446),
start Fri 1/24 19:07, 2 licenses
name3 machine5 NoXDisplay (v2012.12) (server4/port4 10195), start
Wed 1/22 10:30
name3 machine6 NoXDisplay J3_ffffffffa8c0a600_21848_3 (v2012.12)
(server5/port5 6975), start Fri 1/24 9:30
name6 machine7 NoXDisplay (v2012.12) (server6/port6 16114), start
Thu 1/23 15:31"

def check_license_number_each_line(lmstat_line)
lic_used_num_eachline = 0
if lmstat_line =~ /(\d+)\s+licenses/
lic_used_num_eachline = $1.to_i
else
lic_used_num_eachline = 1
end
return lic_used_num_eachline
end

hash_save = Hash.new
string_sample.lines.each do |x|
name = x.split(/\s+/)[1]
if hash_save.include?(name)
hash_save[name] += x
else
hash_save[name] = x
end
end

hash_save.each {|key, value|
account_lic_used = 0
value.each_line {|line|
account_lic_used += check_license_number_each_line(line)
}
hash_save[key] = [value, account_lic_used]
}

a = hash_save.sort_by {|key, value| value[1]}.reverse

puts ‘
puts ‘Sort by license used:’
puts '

a.each {|key, value|
puts ‘==================’
puts “#{key}(#{value[1]})”
puts ‘==================’
puts value[0]
}

On 1/25/14, Previn L. [email protected] wrote:

I wrote a ruby script hash sort related, but feel it’s not good

your code reads fine. and besides, programmers always tend to feel not
*good : )

is it possible to simplify?

possibly. just go slow. sometimes you lose some shortcuts if you’re too
fast.

eg, here is my first shot

def license_cnt line
line =~ /(\d+)\s+licenses/
($1 || 1).to_i
end

hash_names=Hash.new { |hash, key| hash[key] = [[],0] }
lines.each_line {|line|
name, _ = line.split /\s+/, 2
hash_names[name][0] << line
hash_names[name][1] += license_cnt(line)
}

puts ‘
puts ‘Sort by license used:’
puts '

hash_names.
sort_by{|_,v| -v[1]}.
each {|name, value|
puts ‘==================’
puts “#{name} (#{value[1]})”
puts ‘==================’
puts value[0]
}

botp wrote in post #1134375:

def license_cnt line
line =~ /(\d+)\s+licenses/
($1 || 1).to_i
end

hash_names=Hash.new { |hash, key| hash[key] = [[],0] }
lines.each_line {|line|
name, _ = line.split /\s+/, 2
hash_names[name][0] << line
hash_names[name][1] += license_cnt(line)
}

puts ‘
puts ‘Sort by license used:’
puts '

hash_names.
sort_by{|_,v| -v[1]}.
each {|name, value|
puts ‘==================’
puts “#{name} (#{value[1]})”
puts ‘==================’
puts value[0]
}

Dear botp,

I have tested the code, works well, much better than mine, many thanks.

On Sat, Jan 25, 2014 at 9:59 AM, Previn L. [email protected]
wrote:

name3 machine6 NoXDisplay J3_ffffffffa8c0a600_21848_3 (v2012.12)

(server5/port5 6975), start Fri 1/24 9:30
name6 machine7 NoXDisplay (v2012.12) (server6/port6 16114), start
Thu 1/23 15:31"

Hi, this is how I’d do it:

2.0.0p195 :018 > sample = " name1 machin1 NoXDisplay (v2012.12)
(server1/port1 18709), start Fri 1/24 17:26
2.0.0p195 :019"> name2 mchine2 NoXDisplay
J3_ffffffffa8c0a600_21848_2 (v2012.12) (server2/port2 13335), start
Fri 1/24 9:29
2.0.0p195 :020"> name2 machine3 NoXDisplay
J3_ffffffffa8c0a600_21848_1 (v2012.12) (server3/port3 8569), start Fri
1/24 9:26
2.0.0p195 :021"> name1 machine4 NoXDisplay (v2012.12)
(192.168.0.197/27007 38446), start Fri 1/24 19:07, 2 licenses
2.0.0p195 :022"> name3 machine5 NoXDisplay (v2012.12)
(server4/port4 10195), start Wed 1/22 10:30
2.0.0p195 :023"> name3 machine6 NoXDisplay
J3_ffffffffa8c0a600_21848_3 (v2012.12) (server5/port5 6975), start Fri
1/24 9:30
2.0.0p195 :024"> name6 machine7 NoXDisplay (v2012.12)
(server6/port6 16114), start Thu 1/23 15:31"

(I’ve used the rule that when there are licenses in the string, there
are two ‘,’):

2.0.0p195 :038 > licenses = sample.scan(/\s+([^
])[^,],(?:[^,],\s+(\d+) licenses)?.$/)
=> [[“name1”, nil], [“name2”, nil], [“name2”, nil], [“name1”, “2”],
[“name3”, nil], [“name3”, nil], [“name6”, nil]]

The rest is adding together each name and sorting:

2.0.0p195 :039 > h = Hash.new(0)
=> {}
2.0.0p195 :040 > licenses.each {|name, num| h[name] += (num.nil? ? 1 :
num.to_i)}
=> [[“name1”, nil], [“name2”, nil], [“name2”, nil], [“name1”, “2”],
[“name3”, nil], [“name3”, nil], [“name6”, nil]]
2.0.0p195 :041 > h.sort_by {|k,v| -v}
=> [[“name1”, 3], [“name2”, 2], [“name3”, 2], [“name6”, 1]]

Tip: if you want to sort from biggest to smallest, use -v, instead of
sorting and reversing.

Hope this helps,

Jesus.

Jesús Gabriel y Galán wrote in post #1134504:

Hi, this is how I’d do it:

2.0.0p195 :038 > licenses = sample.scan(/\s+([^
])[^,],(?:[^,],\s+(\d+) licenses)?.$/)
=> [[“name1”, nil], [“name2”, nil], [“name2”, nil], [“name1”, “2”],
[“name3”, nil], [“name3”, nil], [“name6”, nil]]

The rest is adding together each name and sorting:

2.0.0p195 :039 > h = Hash.new(0)
=> {}
2.0.0p195 :040 > licenses.each {|name, num| h[name] += (num.nil? ? 1 :
num.to_i)}
=> [[“name1”, nil], [“name2”, nil], [“name2”, nil], [“name1”, “2”],
[“name3”, nil], [“name3”, nil], [“name6”, nil]]
2.0.0p195 :041 > h.sort_by {|k,v| -v}
=> [[“name1”, 3], [“name2”, 2], [“name3”, 2], [“name6”, 1]]

Tip: if you want to sort from biggest to smallest, use -v, instead of
sorting and reversing.

Hope this helps,

Jesus.
Dear Jesus,

This is really helpful, thank you so much!