Ruby - 创建一个哈希,其中Keys是新初始化的Array对象

时间:2013-09-20 20:32:43

标签: ruby arrays hash

请耐心等待......我需要基本的概念......我还没有意识到先进的编程概念。

我有一个名为Circle的类,它初始化并计算area

class Circle
   def initialize (radius)
     @radius = radius
   end


   def area
     3.14*@radius*@radius
   end
end

我想接受用户输入并创建许多Circle个对象及其边的实例。

p "How many Circles"
i = gets.to_i
j = 1

while j != i+1
p "Enter radius of Circle #{j}"
$s << Circle.new(gets.to_i)
j = j +1
end

$s[]现在拥有我创建的对象数组。

现在,我想做点什么,

area_array[] = 0
area_array[Circle1] = Circle1.area
area_array[Circle1] = Circle2.area  

依此类推......其中Circle1和Circle2是我之前在while循环中创建的对象....

有人能告诉我如何将每个创建的对象放在另一个数组中并为其分配区域值?

4 个答案:

答案 0 :(得分:2)

您是否需要另一个阵列,因为您将修改或销毁第一个阵列中Circles的属性?如果是这样,你可以依赖数组中Cirlces的顺序保持不变,那么只需使用索引值来关联这些值:

circle_area_hash = $s.reduce{|a, c| a[c.object_id] = c.area }

另外,考虑到对于您的分析,您可能更关心值,而不是对象本身。那么你可以创建

circle_area_hash = $s.reduce do |a, c| 
  a[c.area] = (a[c.area].nil?) ? [c] : a[c.area] << c 
end

这使得哈希键成为区域值,并且哈希值每个都是具有该区域的对象的数组。

然后到get the key(最大区域)你可以:

circle_area_hash.max_by{|k,v| v.count}

另外,作为一个想法:

puts "How many Circles"
$s = (1...gets.to_i).each |j|
  puts "Enter radius of Circle #{j}"
  $s << Circle.new(gets.to_i)
end

$s[3].area

答案 1 :(得分:2)

创建一个新的区域数组:

area_array = $s.map{ |circle| circle.area }
area_array = $s.map( &:area )               # Same thing, but shorter

创建一个大哈希:

areas = Hash[ $s.map{ |circle| [ circle, circle.area ] } ]

这将创建一个数组数组,如:

[
  [ <Circle @radius=3>, 28.27 ],
  [ <Circle @radius=4>, 50.27 ],
  …
]

...然后使用Hash.[]方法将其转换为哈希。

另一种技巧是:

areas = $s.inject({}){ |hash,circle| hash.merge(circle=>circle.area) }

有关详细信息,请阅读Array#mapEnumerable#inject

但是,为什么要创建此哈希?看起来你可能只希望每次计算一次。虽然这个简单计算不需要它,但您可以使用如下模式记住方法的返回值:

class Circle
  def initialize(radius)
    @radius = radius
  end
  def area
    @area ||= Math::PI*@radius*@radius
  end
end

这将在第一次需要时计算区域,并将其存储在实例变量中;之后它只会使用该变量的值作为方法的返回值,而无需重新计算。

答案 2 :(得分:1)

这非常简单。您应该迭代$s,将每个元素用作哈希键,并将其area的结果作为相应的值。

对你有用的另外几点:

  • 您可以使用Math::PI代替3.14

  • 您应该只使用p进行调试。它打印其参数的inspect方法的结果,这很少是您想要的整洁输出。如果您想在字符串中显示换行符,请使用print;如果还没有换行符,则使用puts附加换行符

  • 在Ruby中使用while很少是合适的。在这种情况下,您只需要i.times do { ... }

class Circle

  def initialize (radius)
    @radius = radius
  end

  def area
    Math::PI * @radius * @radius
  end

end

print 'How many Circles: '
i = gets.to_i

shapes = []
i.times do |n|
  print "Enter radius of Circle #{n+1}? "
  shapes << Circle.new(gets.to_i)
end

area_hash = {}
shapes.each do |shape|
  area_hash[shape] = shape.area
end

然而,在这里记住area方法似乎更合适,将其写为

def area
  @area = Math::PI * @radius * @radius unless @area
  @area
end

然后你可以重复使用这个方法,计算只进行一次。

答案 3 :(得分:0)

在阅读你对NewAlexandria的回答的评论后,或许这样的事情对你有用:

p "How many Circles"
(1..gets.to_i) do |j|
  c = Circle.new
  p "Enter radius of Circle #{j}"
  s[c] = c.area(gets.to_i)}
end

其中s是预定义的哈希值,可能包含其他圆圈,矩形等实例的键。

但是,如果您计划向要使用s键引用的形状类添加其他常量或方法,这才有意义。

您应该编辑您的问题以合并上面的评论。