在数组中找到匹配的对象:数组或对象

时间:2013-09-11 21:28:41

标签: ruby arrays class

我定义了一个班级My_Class。它的一个属性是type:让我们说"A""B""C"。我创建了my_ary个实例的数组My_Class,并根据日期,时间和其他实例数据对其进行了排序。这些项目按特定顺序排列。我想迭代数组,对于"A"类型的每个对象,找到尚未与类型"B"项配对的下一个"A"类型的顺序项,然后将它们配对两件事。正在配对的项目必须是下一个后续配对类型"B"对象。

我可以使用数组上的循环来执行此操作:

(0...my_ary.length) do |idx|
   if (my_ary[idx].type=="A") then
      ...iterate array from idx+1 and find next available type "B", 
         "pair" it to item at idx, and make paired item unavailable 
         for further matching...
   end
end

配对前的数组元素0..6 。每一行都是My_Class对象,而不是Hash。我为每个数组元素使用了BRACKET和类似哈希的键值表示法,因为我不知道如何正确表示对象数组。

idx   data
0     [type:'A' , pairedto:nil , pairedby:nil , '1/1/2000' , ...other data...]
1     [type:'C' , pairedto:nil , pairedby:nil , '1/2/2000' , ...other data...]
2     [type:'A' , pairedto:nil , pairedby:nil , '1/5/2000' , ...other data...]
3     [type:'B' , pairedto:nil , pairedby:nil , '1/5/2000' , ...other data...]
4     [type:'A' , pairedto:nil , pairedby:nil , '1/6/2000' , ...other data...]
5     [type:'B' , pairedto:nil , pairedby:nil , '1/6/2000' , ...other data...]
6     [type:'B' , pairedto:nil , pairedby:nil , '1/8/2000' , ...other data...]
配对后

idx   data
0     [type:'A' , pairedto:3 , pairedby:nil , '1/1/2000' , ...other data...]
1     [type:'C' , pairedto:nil , pairedby:nil , '1/2/2000' , ...other data...]
2     [type:'A' , pairedto:5 , pairedby:nil , '1/5/2000' , ...other data...]
3     [type:'B' , pairedto:nil , pairedby:0 , '1/5/2000' , ...other data...]
4     [type:'A' , pairedto:6 , pairedby:nil , '1/6/2000' , ...other data...]
5     [type:'B' , pairedto:nil , pairedby:2 , '1/6/2000' , ...other data...]
6     [type:'B' , pairedto:nil , pairedby:4 , '1/8/2000' , ...other data...]

我想将部分或全部迭代,限定,搜索和配对逻辑移到类定义中。 我想强调数据和操作并不那么重要 - 我要做的是发现以红宝石为中心或非传统的方法来迭代和分类对象集合。执行工作的实际代码无关紧要。对于这个问题,我看到了两个机会:

我。将数组迭代器保留在主程序中,但扩展类以允许对象搜索数组中的其余对象:对于每个类型"A"项,找到下一个可用类型"B",并将其自身配对那个对象:

    (0...my_ary.length) do |idx| 
      if (my_ary[idx].type=="A") then my_ary[idx].pair_yourself(y_ary,idx) end 
    end 

II。将主程序数组迭代器移动到类方法并与选项1结合。让类处理所有内容。主程序说:

    My_Class.go_pair_all_items_in_array(my_ary)

问题:

  1. 在方法2中,让My_Class负责迭代未知形状和形式的数组是否公平?假设传入的任何数组都是My_Class项或从中派生的。我很确定Class方法有一种方法可以确定传入的数组是否包含从自身派生的元素。
  2. 还有其他非传统方法吗?我知道我可以为数组创建一个类,并让它处理列表迭代,但这似乎不足以进行心理挑战。

1 个答案:

答案 0 :(得分:1)

我猜你是Java或C ++程序员,因为你的想法是以类为中心的。

Ruby方式是鸭子打字。要使分类配对工作,您只需要知道列表respond_to?type方法以及pairedby=中的项目。将数组作为混合实现此操作将是非常标准的Ruby。

除非需要访问内部函数,即pair_with_next,否则您不应该在两个类之间拆分这样的简单功能。

一个原因:当O(n)很难获得时,通过分割函数,你自己就会对O(n ^ 2)性能下降很多。一次通过。保留A索引的队列。当您看到B时,从队列中删除头索引。这是与当前B匹配的A.继续直到完成。如果队列为空,则为匹配的A分配nil .Ruby数组很容易实现队列。

混合使用看起来像:

class Array
  def pairable_by_type?
    all? {|i| [:type, :pairedby=].all?{|t| i.respond_to? t } }
  end

  def pair_by_type(a='A', b='B')
    q = []
    each_with_index do |item, i|
      item.pairedby = nil  # clear previous pairing
      case item.type
        when a
          q << i
        when b
          item.pairedby = q.shift
      end
    end
  end
end

我没有对此进行测试,但它应该接近。你只需说my_ary.pair_by_type即可完成工作。另外my_ary.pairable_by_type?会告诉你它是可行的。

此混合将配对功能添加到应用程序中的所有数组。有些人可能会觉得这很令人反感。为了避免它,

class Array
  def self.new_pairable
    ary = []  
    def ary.pair_by_type(a='A', b='B')
      q = []
      each_with_index do |item, i|
        item.pairedby = nil  # clear previous pairing
        case item.type
          when a
            q << i
          when b
            item.pairedby = q.shift
        end
      end
    end
    ary
  end
end

现在您可以说my_ary = Array.new_pairable然后my_ary.pair_by_type。但通常创建的数组不会有pair_by_type方法。