简体   繁体   English

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

[英]Ruby - Create a hash, where Keys are newly initialized Array objects

Please bear with me...I need basic concepts...I am not aware of advanced prog concepts yet. 请忍受...我需要基本概念...我还不知道高级编概念。

I have a class called Circle which initializes and calculates area 我有一个叫做Circle的类,它可以初始化和计算area

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


   def area
     3.14*@radius*@radius
   end
end

I want to take user input and create however many instances of Circle objects and its sides. 我想接受用户输入并创建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

The $s[] now holds array of objects I created. $s[]现在保存我创建的对象数组。

Now, I want to do something like, 现在,我想做类似的事情,

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

and so on...where Circle1 and Circle2 are the objects I created earlier in my while loop.... 依此类推...其中Circle1和Circle2是我在while循环中先前创建的对象。

Can someone tell me how can I put each of the created object in another array and assign an area value to it? 有人可以告诉我如何将每个创建的对象放在另一个数组中并为其分配区域值吗?

Do you need another array because you will modify or destroy the properties of the Circles in the first array? 您是否需要另一个数组,因为您将在第一个数组中修改或破坏Circles的属性? If so, and you can rely on the Cirlces' order in the array remaining the same, then just use the index value to correlate the values: 如果是这样,您可以依靠数组中Cirlces的顺序保持不变,则只需使用索引值将这些值关联起来即可:

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

Also, consider that for your analyses, you may care more about the values, than the objects, per se . 另外,考虑到进行分析时,您可能更关心值而不是对象本身 So then you could create 这样就可以创建

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

This make the hash-keys bey the area value as, and the hash-values are each an array of the objects that have that area. 这使哈希键成为区域值,哈希值分别是具有该区域的对象的数组。

Then to get the key (largest area) you can: 然后,要获取密钥 (最大区域),您可以:

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

Also, as a thought: 另外,作为一个想法:

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

To create a new array of areas: 要创建新的区域数组:

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

To create one big hash: 要创建一个大哈希:

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

This creates an array of arrays like: 这将创建一个数组数组,例如:

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

…and then uses the Hash.[] method to convert that into a Hash. …然后使用Hash.[]方法将其转换为Hash。

Another technique is: 另一种技术是:

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

For more details, read up on Array#map and Enumerable#inject . 有关更多详细信息,请阅读Array#mapEnumerable#inject

However, why would you want to create this hash? 但是,为什么要创建此哈希? It seems like you're perhaps wanting to only calculate the area once each. 似乎您可能只想每个计算一次面积。 Although it's not needed for this simple calculation, you can memoize a method's return value with a pattern like this: 尽管此简单计算不需要它,但您可以使用以下模式来记忆方法的返回值:

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

This will calculate the area the first time it's needed, and store it in an instance variable; 这将在第一次需要时计算面积,并将其存储在实例变量中; thereafter it will just use the value of that variable as the return value of the method, without needing to recalculate it. 之后,它将仅使用该变量的值作为方法的返回值,而无需重新计算它。

This is very straightforward. 这很简单。 You should just iterate over $s , using each element as a hash key and the result of its area as the corresponding value. 您应该仅在$s进行迭代,将每个元素用作哈希键,并将其area的结果用作相应的值。

Another few points that should be useful to you: 还有几点对您有用:

  • You can use Math::PI instead of 3.14 您可以使用Math::PI而不是3.14

  • You should only use p for debugging. 您只应使用p进行调试。 It prints the result of the inspect method of its parameter, which is rarely what you want for tidy output. 它打印其参数的inspect方法的结果,这很少是您想要整洁输出的结果。 Use print if you want to make your newlines explicit in the string, or puts to append a newline if there isn't one already 使用print ,如果你想使你的换行符明确字符串中,或puts追加一个换行符如果没有一个已

  • It is rarely appropriate to use while in Ruby. 这是很少适合使用while在Ruby中。 In this instance you just want i.times do { ... } 在这种情况下,您只想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

However it seems more appropriate to memoize the area method here, writing it as 但是,似乎更适合在此处记住area方法,将其写为

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

Then you can use the method repeatedly and the calculation will be done only once. 然后,您可以重复使用该方法,并且计算将仅执行一次。

After reading your comment on NewAlexandria's answer, perhaps something like this would work for you: 在阅读了您对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

where s is a pre-defined hash that may contain keys for instances of other circles, rectangles, etc. 其中s是预定义的哈希,其中可能包含其他圆形,矩形等的实例的键。

This only makes sense, however, if you plan to add additional constants or methods to your shape classes that you will want to reference with the keys of s . 但是,仅当您计划向形状类添加其他常量或方法时,才需要使用s的键进行引用,这才有意义。

You should edit your question to incorporate your comment above. 您应该编辑问题以纳入上面的评论。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM