【问题标题】:How do I extract and sort the instance variables of one class, that are stored in an array inside of an instance variable in another class using ruby?如何使用 ruby​​ 提取和排序一个类的实例变量,这些实例变量存储在另一个类的实例变量内部的数组中?
【发布时间】:2020-08-04 23:22:13
【问题描述】:

在了解更多关于 Ruby 的信息时,我遇到了困难。我正在尝试提取和排序一个类的实例变量的值,该值存储在另一个类的实例变量内的数组中。我似乎只能抓取类本身的实例,而不是类中的具体实例变量。

下面是两个类。

product.rb

class Product
  attr_reader :name,
              :price

  def initialize(name, price)
    @name = name
    @price = price
  end
end

catalogue.rb

class Catalogue
  attr_reader :contents

  def initialize
    @contents = []
  end

  def cheapest
    @contents.product.first
  end

  def <<(product)
    @contents << product
  end
end

以下测试确认我没有正确地提取和排序 @name@priceProduct 实例,存储在 @contents 实例中的 Catalogue 中。

catalogue_test.rb

gem 'minitest', '~> 5.2'                                                             
require 'minitest/autorun'                                                           
require 'minitest/pride'  
require 'catalogue'
require 'product'

class CatalogueTest < Minitest::Test                                                 
  def test_cheapest_of_one                                                           
    catalogue = Catalogue.new                                                        
    catalogue << Product.new('scissors', 8)                                          
    assert_equal 'scissors', catalogue.cheapest                                      
  end                                                                          
end

这是失败:

Failure:
CatalogueTest#test_cheapest_of_one [catalogue_test.rb:16]:
--- expected
+++ actual
@@ -1 +1 @@
-"scissors"
+[#<Product:0xXXXXXX @name="scissors", @price=8>]

理想情况下,我希望能够在多个实例中根据价格提取和分类产品。我意识到我需要进一步扩展现有代码以确保我获得最便宜的(当数组中有多个对象时),但只是尝试从一个基本函数开始访问其中的元素。

到目前为止,我已经尝试了一些不同的方法,例如 sortfirst,但是,我无法超越上述输出 [#&lt;Product:0xXXXXXX @name="scissors", @price=8&gt;],并深入研究实例变量。 ????‍♂️

我需要在catalogue.rb 中添加什么才能使catalogue_test.rb 中的test_cheapest_of_one 通过?

【问题讨论】:

  • 在您的测试中,您正在测试Product 是否等于String。显然,Product永远不会等于StringProduct 将仅等于 ProductString 将仅等于 String
  • 感谢您帮助我。是的,正在考虑需要修改 cheapest 方法以从 [#&lt;Product:0xXXXXXX @name="scissors", @price=8&gt;] 中抓取“剪刀”。
  • 为了清楚起见,您尝试在类的实例上使用 getter 方法,而不是尝试读取其实例变量。如果您试图读取实例变量,那将是封装不当的问题。 Getter 方法可以选择公开实例变量,但不是必须的。
  • @anothermh 感谢您的澄清。我不确定我应该尝试使用什么方法。

标签: arrays ruby sorting instance instance-variables


【解决方案1】:

我认为您的测试将使用以下方法定义:

def cheapest
  @contents.sort_by(&:price).reverse.first.name
end

或者

def cheapest
  @contents.sort_by { |product| produce.price * -1 }.first.name
end

目前您正在尝试调用@contents.product,实际上是在调用Array#product - 这不是您想要的。

【讨论】:

  • @en1on 很高兴它成功了。您也可以使用max_by 代替sort_by...first
【解决方案2】:

在你的问题中,你问:

我需要在catalogue.rb 中添加什么才能使catalogue_test.rb 中的test_cheapest_of_one 通过?

但是,这是一个错误的问题!正如我在my comment above 中提到的,您的问题是,在您的测试中,您正在测试Product 是否等于String,这永远不会 成为true,因为产品永远不会等于字符串。一个产品只能等于一个产品,一个字符串只能等于一个字符串。

所以,问题在于您的测试,而不是生产代码。

如果您要修改生产代码,则必须更改cheapest 方法以返回最便宜产品的名称。但这是错误。它应该返回最便宜的产品。如果它返回名称,它对您没有帮助,因为您对名称没有任何用处。您无法打印出最便宜的产品的成本,例如,因为您不知道最便宜的产品是什么,您只知道它叫什么。

正确的解决方案是修改测试,使其测试返回的是正确的产品,而不是名称:

def test_cheapest_of_one
  catalogue = Catalogue.new
  scissors  = Product.new('scissors', 8)
  catalogue << scissors

  assert_equal scissors, catalogue.cheapest
end

【讨论】:

  • 感谢您的解释。
猜你喜欢
  • 2015-06-09
  • 2023-03-28
  • 2014-09-21
  • 1970-01-01
  • 2018-07-25
  • 2013-12-07
  • 1970-01-01
  • 2021-05-11
  • 2023-03-08
相关资源
最近更新 更多