объединять подобные хэши в ruby?

Я пытался и пытался, но я не могу сделать это менее уродливым / более рубиновым. Кажется, должен быть лучший путь. Помоги мне учиться.

class Df
  attr_accessor :thresh
  attr_reader :dfo

  def initialize
      @dfo    = []
      @df     = '/opt/TWWfsw/bin/gdf'

      case RUBY_PLATFORM
      when /hpux/i
          @fstyp = 'vxfs'
      when /solaris/i
          # fix: need /tmp too
          @fstyp = 'ufs'
      when /linux/i
          @df = '/bin/df'
          @fstyp = 'ext3'
      end
      @dfo  = parsedf
  end
  def parsedf
      ldf = []
      [" "," -i"] .each do |arg|
          fields = %w{device size used avail capp mount}
          fields = %w{device inodes inodesused inodesavail iusep mount} if arg == ' -i'
          ldf.push %x{#{@df} -P -t #{@fstyp}#{arg}}.split(/\n/)[1..-1].collect{|line| Hash[*fields.zip(line.split).flatten]}
      end
      out = []
      # surely there must be an easier way
      ldf[0].each do |x|
          ldf[1].select { |y|
              if y['device'] == x['device']
                  out.push x.merge(y)
              end
          }
      end
      out
  end
end
10.11.2009 20:28:53
Вы должны объяснить, что вы собираетесь делать.
johannes 11.11.2009 11:34:57
2 ОТВЕТА

На моей машине ваш массив ldf после вызовов df выдает следующее:

irb(main):011:0> ldf
=> [[{"device"=>"/dev/sda5", "size"=>"49399372", "mount"=>"/", "avail"=>"22728988", "used"=>"24161036", "capp"=>"52%"}], [{"device"=>"/dev/sda5", "inodes"=>"3137536", "mount"=>"/", "iusep"=>"13%", "inodesavail"=>"2752040", "inodesused"=>"385496"}]]

Наиболее гибкий подход к объединению такой структуры, вероятно, примерно такой:

irb(main):013:0> ldf.flatten.inject {|a,b| a.merge(b)}
=> {"device"=>"/dev/sda5", "inodes"=>"3137536", "size"=>"49399372", "mount"=>"/", "avail"=>"22728988", "inodesavail"=>"2752040", "iusep"=>"13%", "used"=>"24161036", "capp"=>"52%", "inodesused"=>"385496"}

Некоторые программисты ruby ​​недовольны этим использованием inject, но мне это нравится, поэтому ваш пробег может отличаться.

Что касается того, как сделать ваш код более похожим на ruby, я предлагаю вам поговорить с опытным rubyist, которого вы, возможно, знаете по своему коду, чтобы помочь вам переписать его так, чтобы он следовал хорошему стилю и лучшим практикам. Вероятно, это было бы предпочтительнее, чем просто попросить кого-то переписать это для вас здесь.

Удачи!

1
10.11.2009 22:09:24

Не тестировал код, но здесь идет:

ARGUMENTS = {
  " "   => %w{size used avail capp mount},
  " -i" => %w{inodes inodesused inodesavail iusep mount}
}

def parsedf
  # Store resulting info in a hash:
  device_info = Hash.new do |h, dev|
    h[dev] = {} # Each value will be a empty hash by default
  end

  ARGUMENTS.each do |arg, fields|
    %x{#{@df} -P -t #{@fstyp}#{arg}}.split(/\n/)[1..-1].each do |line|
      device, *data = line.split
      device_info[device].merge! Hash[fields.zip(data)]
    end
  end
  device_info
end

Примечания: возвращает что-то немного отличное от того, что было у вас:

{ "/dev/sda5" => {"inodes" => "...", ...},
  "other device" => {...}
}

Кроме того, я предполагаю, что Ruby 1.8.7 или лучше Hash[key_value_pairs], иначе вы можете прибегнуть к Hash[*key_value_pairs.flatten]форме, которую вы имели

В зависимости от ваших потребностей, вы должны рассмотреть возможность переключения полей со строки на символы; это лучший тип ключей.

2
20.02.2013 15:44:36
Работал отлично! Спасибо за указатель на другой сайт. Я не слышал об этом.
sam 11.11.2009 15:01:09