Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使我的第一次Ruby工作更加地道_Ruby - Fatal编程技术网

如何使我的第一次Ruby工作更加地道

如何使我的第一次Ruby工作更加地道,ruby,Ruby,为我的新工作挑选Ruby会很有帮助,所以今天早上我写了以下内容。它需要一个我玩过的国际象棋的PGN文件,并通过第一步对它们进行索引。如果能给我一些建议,让它更“地道”,我将不胜感激 因为它不接受命令行参数(例如文件名参数),也不是面向对象的参数,所以我们当然欢迎使用这些参数 记住,我正在创建一个所有游戏中所有动作(不仅仅是第一步)的索引,因为我希望最终索引的不仅仅是第一步 数据遵循代码 games = [] file = File.new("jemptymethod.pgn", "r") is

为我的新工作挑选Ruby会很有帮助,所以今天早上我写了以下内容。它需要一个我玩过的国际象棋的PGN文件,并通过第一步对它们进行索引。如果能给我一些建议,让它更“地道”,我将不胜感激

因为它不接受命令行参数(例如文件名参数),也不是面向对象的参数,所以我们当然欢迎使用这些参数

记住,我正在创建一个所有游戏中所有动作(不仅仅是第一步)的索引,因为我希望最终索引的不仅仅是第一步

数据遵循代码

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