我有一个班级,有50个随机分数,随机分数,存储在哈希数组中:
def initialize
# adding fake names and numbers
require 'faker'
@people = []
(1..50).each do
@people << { name: Faker::Name.first_name, score: Faker::Number.between(1, 1000).to_i }
end
end
特别是top
方法(下面)将返回字符串中排名前N位的人。作为一个更新的红宝石,我认为可能有一种方法可以使这更简单。这是方法:
def top(number=10)
top_people = @people.group_by { |person| person[:score] }
.sort_by { |key, value| -key } # largest -> smallest
.first(number)
.map(&:last)
.flatten
.map { |person| "#{person[:name]} (#{person[:score]})" }
.join(", ")
puts "The top #{number} are here: #{top_people}"
end
供参考,使用Ruby 2.3.3
答案 0 :(得分:1)
将业务逻辑(如何获得最佳人才)与输出(如何显示人员列表)混合起来可能不是一个好主意。您可以通过组合sort_by / group_by并使用flat_map
:
class MyClass
def top number=10
top_groups = @people.group_by { |person| person[:score] }.max_by(number, &:first)
top_groups.flat_map(&:last)
end
def self.show_people people
people.map { |person| "%{name} (%{score})" % person }.join(", ")
end
end
some_class = MyClass.new
top_people = some_class.top 10
puts "The top #{top_people.size} people are #{MyClass.show_people(top_people)}"
答案 1 :(得分:1)
Be Welcoming是我们的新动力,所以这里......
当您提出问题时,请确保它是一个完整且实用的问题。例如“我有一个有50个随机分组的班级,随机分数存储在哈希数组中:[...]特别是顶级方法将返回带有分数的字符串中的前N个人。”
请向我们提供一个课程:
# require your dependencies outside of the class
# this is where they will end up anyway and it makes it easier for us
# to find them
require 'faker'
class Scoreboard
def initialize
# adding fake names and numbers
@people = []
(1..50).each do
@people << { name: Faker::Name.first_name,
score: Faker::Number.between(1, 1000).to_i }
end
end
def top(number=10)
top_people = @people.group_by { |person| person[:score] }
.sort_by { |key, value| -key } # largest -> smallest
.first(number)
.map(&:last)
.flatten
.map { |person| "#{person[:name]} (#{person[:score]})" }
.join(", ")
puts "The top #{number} are here: #{top_people}"
end
end
现在让我们在Scoreboard#top
步骤:
Hash
Array
这看起来有点矫枉过正。让我们通过找到切断来尝试不同的解决方案
def cut(n=10)
@people.map {|p| p[:score]}.uniq.sort.last(n).first
end
现在我们知道我们将接受的最小分数,所以现在只需要那些people
def top(n=10)
top_people = @people.select {|p| p[:score] >= cut(n) }
.sort_by {|p| -p[:score]}
.map { |person| "#{person[:name]} (#{person[:score]})" }
puts "The top #{n} are here: #{top_people.join(',')}"
end
现在看起来有点干净,但People
不应该降级到字典(毕竟我们有感情)所以让它们成为真正的Object
(顺便说一句,人们在现实生活中仍然是错的)。由于它们是只有first_name
和score
Struct
的简单生物,所以会很好。
Person = Struct.new(:name, :score)
这实际上创建了一个看起来像这样的对象
class Person
attr_accessor :name, :score
def initialize(name,score)
@name = name
@score = score
end
end
现在我们可以像这样创造我们的人
def initialize
# we will use Enumerable#map rather than initializing an Array
# and pushing into it
@people = (1..50).map do
Person.new(Faker::Name.first_name,
Faker::Number.between(1, 1000).to_i)
end
end
现在而不是Hash#[]
访问权限我们有score
和name
的方法,所以我们可以使用一些Symbol#to_proc
糖(现在不要担心这个但是请随意调查它,因为它是非常红宝石的惯用语)
def cut(n=10)
@people.map(&:score).uniq.sort.last(n).first
end
def top(n=10)
top_people = @people.select {|p| p.score >= cut(n) }
.sort_by(&:score).reverse
.map { |person| "#{person.name} (#{person.score})" }
puts "The top #{n} are here: #{top_people.join(',')}"
end
我们现在几乎就在那里,但这个"#{person.name} (#{person.score})"
似乎很愚蠢,因为这些是唯一的属性,所以让我们通过为{Person
定义to_s
来使其成为Person
的默认表示。 1}}
Person = Struct.new(:name, :score) do
def to_s
"#{name} (#{score})"
end
end
现在我们有了
def top(n=10)
top_people = @people.select {|p| p.score >= cut(n) }
.sort_by(&:score).reverse
end
此外,由于puts
返回nil
,您可以在其他地方处理显示,我已删除puts
语句。由于您已经从电话会议外了解n
,我建议您使用以下内容:
n = 12
puts "The top #{n} people are:"
puts Scoreboard.new.top(n)
哦,现在这么干净了。希望你喜欢这个答案并一路上学到一些东西。 Full Example
答案 2 :(得分:1)
我也试图改善其他事情。我想念更多的背景,但作为理论练习回答你的问题,这就是我要做的事情:
require 'faker'
class ScoredPerson
attr_reader :name
attr_reader :score
def initialize
@name = Faker::Name.first_name
@score = Faker::Number.between(1, 1000).to_i
end
end
class TopPeople
attr_accessor :people
def initialize
@people = 50.times.map do
ScoredPerson.new
end.sort_by { |p| p.score }.reverse
end
def top(number=10)
people.first(number)
.map { |p| "#{p.name} (#{p.score})"}.join(", ")
end
end
top
方法时订购。ScoredPerson
类来封装得分人的逻辑。