如何使我的第一次Ruby工作更加地道
为我的新工作挑选Ruby会很有帮助,所以今天早上我写了以下内容。它需要一个我玩过的国际象棋的PGN文件,并通过第一步对它们进行索引。如果能给我一些建议,让它更“地道”,我将不胜感激 因为它不接受命令行参数(例如文件名参数),也不是面向对象的参数,所以我们当然欢迎使用这些参数 记住,我正在创建一个所有游戏中所有动作(不仅仅是第一步)的索引,因为我希望最终索引的不仅仅是第一步 数据遵循代码如何使我的第一次Ruby工作更加地道,ruby,Ruby,为我的新工作挑选Ruby会很有帮助,所以今天早上我写了以下内容。它需要一个我玩过的国际象棋的PGN文件,并通过第一步对它们进行索引。如果能给我一些建议,让它更“地道”,我将不胜感激 因为它不接受命令行参数(例如文件名参数),也不是面向对象的参数,所以我们当然欢迎使用这些参数 记住,我正在创建一个所有游戏中所有动作(不仅仅是第一步)的索引,因为我希望最终索引的不仅仅是第一步 数据遵循代码 games = [] file = File.new("jemptymethod.pgn", "r") is
games = []
file = File.new("jemptymethod.pgn", "r")
is_header = false
is_score = false
Game = Struct::new(:header, :score)
while (line = file.gets)
if !line.chomp.empty?
if !is_score && !is_header
game = Game::new('','')
end
if /^\[/.match(line)
is_header = true
game.header << line
else
is_score = true
game.score << line
end
else
if is_score
is_score = false
is_header = false
games << game
end
end
end
file.close
puts "# Games: " + games.length.to_s
moves_index = {}
first_moves = {}
games.each { |gm|
#the following output should essentially be lossless
#with the possible exception of beginning or ending newlines
#
#puts gm.header + "\n"
#puts gm.score + "\n"
score_tokens = gm.score.split(/\s+/);
game_moves = []
score_tokens.each_index{|i|
if i%3 != 0
move_token = score_tokens[i]
if !moves_index.has_key?(move_token)
moves_index[move_token] = moves_index.keys.length
end
game_moves << moves_index[move_token]
end
}
first_move = moves_index.index(game_moves[0])
if !first_moves.has_key?(first_move)
first_moves[first_move] = 1
else
first_moves[first_move] = 1 + first_moves[first_move]
end
}
# sorting hashes by value: http://nhw.pl/wp/2007/06/11/sorting-hash-by-values
first_moves.sort{|a,b| -1*(a[1]<=>b[1])}.each{|k,v|
puts "1. #{k} occurred #{v} times"
}
这里有一个快速的解决方案,我将如何做到这一点。这里可能有很多东西需要消化,所以请随意提问,但是阅读Ruby或文档应该可以回答大多数关于我所做的事情的问题,并且有大量关于Ruby类的好教程。这对于理解我在这里的类中而不是在结构中使用的访问器是一个很好的方法
class Game
attr_accessor :header, :moves
def initialize
self.header = []
end
end
games = []
game = Game.new
File.open('jemptymethod.pgn').each_line do |line|
next if line.chomp.empty?
if game.moves
games << game
game = Game.new
end
if /^\[/.match(line)
game.header << line
else
moves = line.split(/\d+\.\s*/) # splitting on the move numbers so that we don't have to iterate through to remove them
moves.shift # getting rid of first empty move since the split on '1. ' created an array element before the '1. '
game.moves = moves
end
end
games << game # add last game since the first part of the file loop doesn't execute again to do it
puts "# Games: " + games.length.to_s
first_moves = games.map {|game| game.moves[0]} # Could easily iterate over the size of the longest game to get other moves (eg second move, etc)
first_moves_count = first_moves.inject(Hash.new(0)) {|h, move| h[move] += 1; h} # Read ruby documentation on inject to see how this works
first_moves_count.each do |move, count|
puts "1. #{move} occurred #{count} times"
end
类游戏
属性访问器:标题,:移动
def初始化
self.header=[]
结束
结束
游戏=[]
game=game.new
File.open('jemptymethod.pgn')。每行|
下一个if line.chomp.empty?
如果游戏移动
游戏这里有一个快速的解决方案,我将如何做到这一点。这里可能有很多东西需要消化,所以请随意提问,但是阅读Ruby或文档应该可以回答大多数关于我所做的事情的问题,并且有大量关于Ruby类的好教程。这对于理解我在这里的类中而不是在结构中使用的访问器是一个很好的方法
class Game
attr_accessor :header, :moves
def initialize
self.header = []
end
end
games = []
game = Game.new
File.open('jemptymethod.pgn').each_line do |line|
next if line.chomp.empty?
if game.moves
games << game
game = Game.new
end
if /^\[/.match(line)
game.header << line
else
moves = line.split(/\d+\.\s*/) # splitting on the move numbers so that we don't have to iterate through to remove them
moves.shift # getting rid of first empty move since the split on '1. ' created an array element before the '1. '
game.moves = moves
end
end
games << game # add last game since the first part of the file loop doesn't execute again to do it
puts "# Games: " + games.length.to_s
first_moves = games.map {|game| game.moves[0]} # Could easily iterate over the size of the longest game to get other moves (eg second move, etc)
first_moves_count = first_moves.inject(Hash.new(0)) {|h, move| h[move] += 1; h} # Read ruby documentation on inject to see how this works
first_moves_count.each do |move, count|
puts "1. #{move} occurred #{count} times"
end
类游戏
属性访问器:标题,:移动
def初始化
self.header=[]
结束
结束
游戏=[]
game=game.new
File.open('jemptymethod.pgn')。每行|
下一个if line.chomp.empty?
如果游戏移动
games我还没有完成完整的重构,因为我想保留足够多的原始代码,以免太混乱。主要的变化是引入了一个处理解析的Game
类。这个类的实现可以得到很大的改进,但是它可以在不太修改代码的情况下工作。还有一些小问题:
- 不要使用
File.new
,而是使用File.open
读取文件,并给它一个包含File
参数的块。文件将在块的末尾自动关闭
- 使用
a+=1
代替a=a+1
我做了一个简单的记号,写了一个字母。您可能希望查看该代码以获得解析游戏移动的示例。实际上,这和你正在做的非常相似。大部分代码位于/lib
目录中。解析逻辑在parser.rb中,游戏组件在其他文件中。我鼓励你以类似的方式打破你的国际象棋游戏,增加一个Move
类
总之,下面是我对您的代码的一半重构:
class Game
attr_accessor :header, :score, :moves
def initialize
@header = ""
@score = ""
@moves = []
end
def first_move
moves_index.index(moves[0])
end
def moves_index
moves_index = {}
score.split(/\s+/).each_with_index do |move,i|
if i%3 != 0
unless moves_index.has_key?(move)
moves_index[move] = moves_index.keys.length
end
moves << moves_index[move]
end
end
moves_index
end
end
games = []
is_header = false
is_score = false
File.open("jemptymethod.pgn") do |file|
while (line = file.gets)
if !line.chomp.empty?
if !is_score && !is_header
game = Game.new
end
if line[0,1] == '['
is_header = true
game.header << line
else
is_score = true
game.score << line
end
elsif is_score
is_score = false
is_header = false
games << game
end
end
end
puts "# Games: " + games.length.to_s
first_moves = {}
#the following output should essentially be lossless
#with the possible exception of beginning or ending newlines
#
#puts gm.header + "\n"
#puts gm.score + "\n"
games.each do |gm|
if !first_moves.has_key?(gm.first_move)
first_moves[gm.first_move] = 1
else
first_moves[gm.first_move] += 1
end
end
# sorting hashes by value: http://nhw.pl/wp/2007/06/11/sorting-hash-by-values
first_moves.sort{|a,b| -1*(a[1]<=>b[1])}.each{|k,v|
puts "1. #{k} occurred #{v} times"
}
类游戏
属性访问器:标题,:分数,:移动
def初始化
@header=“”
@score=“”
@移动=[]
结束
第一步
移动索引。索引(移动[0])
结束
def-u索引
移动_索引={}
分数.分割(/\s+/)。每个带有索引的|移动,i|
如果我是%3!=0
除非移动索引。有键?(移动)
移动索引[移动]=移动索引.keys.length
结束
moves我还没有完成完整的重构,因为我想保持足够多的原始代码完好无损,以免太混乱。主要的变化是引入了一个处理解析的Game
类。这个类的实现可以得到很大的改进,但是它可以在不太修改代码的情况下工作。还有一些小问题:
- 不要使用
File.new
,而是使用File.open
读取文件,并给它一个包含File
参数的块。文件将在块的末尾自动关闭
- 使用
a+=1
代替a=a+1
我做了一个简单的记号,写了一个字母。您可能希望查看该代码以获得解析游戏移动的示例。实际上,这和你正在做的非常相似。大部分代码位于/lib
目录中。解析逻辑在parser.rb中,游戏组件在其他文件中。我鼓励你以类似的方式打破你的国际象棋游戏,增加一个Move
类
总之,下面是我对您的代码的一半重构:
class Game
attr_accessor :header, :score, :moves
def initialize
@header = ""
@score = ""
@moves = []
end
def first_move
moves_index.index(moves[0])
end
def moves_index
moves_index = {}
score.split(/\s+/).each_with_index do |move,i|
if i%3 != 0
unless moves_index.has_key?(move)
moves_index[move] = moves_index.keys.length
end
moves << moves_index[move]
end
end
moves_index
end
end
games = []
is_header = false
is_score = false
File.open("jemptymethod.pgn") do |file|
while (line = file.gets)
if !line.chomp.empty?
if !is_score && !is_header
game = Game.new
end
if line[0,1] == '['
is_header = true
game.header << line
else
is_score = true
game.score << line
end
elsif is_score
is_score = false
is_header = false
games << game
end
end
end
puts "# Games: " + games.length.to_s
first_moves = {}
#the following output should essentially be lossless
#with the possible exception of beginning or ending newlines
#
#puts gm.header + "\n"
#puts gm.score + "\n"
games.each do |gm|
if !first_moves.has_key?(gm.first_move)
first_moves[gm.first_move] = 1
else
first_moves[gm.first_move] += 1
end
end
# sorting hashes by value: http://nhw.pl/wp/2007/06/11/sorting-hash-by-values
first_moves.sort{|a,b| -1*(a[1]<=>b[1])}.each{|k,v|
puts "1. #{k} occurred #{v} times"
}
类游戏
属性访问器:标题,:分数,:移动
def初始化
@header=“”
@score=“”
@移动=[]
结束
第一步
移动索引。索引(移动[0])
结束
def-u索引
移动_索引={}
分数.分割(/\s+/)。每个带有索引的|移动,i|
如果我是%3!=0
除非移动索引。有键?(移动)
移动索引[移动]=移动索引.keys.length
结束
我不同意责骂一个不熟悉这门语言的人,寻找代码的反馈。他有工作代码,所以他并不是要求任何人为他做工作,他只是在寻找更好的方法,这很好。如果你想建议他去别处看看,至少建议他去哪里。是的,这也不像他刚注册的那样——他为别人做了他自己那份“免费”的工作。@mmrobins和Alex R,我很感激你的回答,他们可能需要一些时间来消化。我不同意责难一个不懂这门语言的人来寻求代码反馈。他有工作代码,所以他并不是要求任何人为他做工作,他只是在寻找更好的方法,这很好。如果你要建议他去别处,至少建议他去哪里。是的,这也不像他刚注册的那样——他为别人做了他自己那份“免费”的工作。@Mmrbins和Alex R,我感谢你的回答,它们可能需要一些时间来消化。我接受这个,因为它产生的输出与我的原始程序相同。我接受这个,因为它产生sam