Ruby:想要一个类似集合的对象来保持秩序吗

Ruby:想要一个类似集合的对象来保持秩序吗,ruby,arrays,set,Ruby,Arrays,Set,。。。或者,一个防止重复条目的数组 Ruby中是否有某种对象: 据我所知,对[]、[]]和的响应不是很高,但你也不难做出自己的反应。只需将数组子类化,并使用一个集合来维护唯一性约束 一个关于无声下降的问题。这将如何影响#[]=?如果我试图用已经存储在别处的内容覆盖现有条目,它是否应该删除willberemove元素?我认为任何一种方法都可能带来令人不快的惊喜。据我所知,没有一种方法是无序的(或者至少在实现上,意味着不保证顺序——事实上,它通常是作为哈希表实现的,所以它会打乱顺序) 然而,直接扩

。。。或者,一个防止重复条目的数组

Ruby中是否有某种对象:

  • 据我所知,对[]、[]]和的响应不是很高,但你也不难做出自己的反应。只需将数组子类化,并使用一个集合来维护唯一性约束


    一个关于无声下降的问题。这将如何影响#[]=?如果我试图用已经存储在别处的内容覆盖现有条目,它是否应该删除willberemove元素?我认为任何一种方法都可能带来令人不快的惊喜。

    据我所知,没有一种方法是无序的(或者至少在实现上,意味着不保证顺序——事实上,它通常是作为哈希表实现的,所以它会打乱顺序)

    然而,直接扩展数组或将其子类化来实现这一点并不困难。我刚试过,效果很好:

    class UniqueArray < Array
      def initialize(*args)
        if args.size == 1 and args[0].is_a? Array then
          super(args[0].uniq)
        else
          super(*args)
        end
      end
    
      def insert(i, v)
        super(i, v) unless include?(v)
      end
    
      def <<(v)
        super(v) unless include?(v)
      end
    
      def []=(*args)
        # note: could just call super(*args) then uniq!, but this is faster
    
        # there are three different versions of this call:
        # 1. start, length, value
        # 2. index, value
        # 3. range, value
        # We just need to get the value
        v = case args.size
          when 3 then args[2]
          when 2 then args[1]
          else nil
        end
    
        super(*args) if v.nil? or not include?(v)
      end
    end
    
    class UniqueArraydef可以使用散列存储值,并在每个散列对的值中存储递增值。然后,您可以通过对象的值访问对象,以排序的方式访问集合,尽管速度较慢

    稍后我将尝试在这里添加一些代码以进一步解释

    我知道通过值访问要比通过键访问慢得多


    更新1:在Ruby 1.9中,哈希元素按插入顺序进行迭代。

    我喜欢这个解决方案,尽管它需要活动\u支持的OrderedHash

    require 'active_support/ordered_hash'
    
    class OrderedSet < Set
    
      def initialize enum = nil, &block
        @hash = ActiveSupport::OrderedHash.new
        super
      end
    
    end
    
    需要“活动\u支持/有序\u散列”
    类OrderedSet

    =)

    从Ruby 1.9开始,内置的
    散列
    对象保留插入顺序。例如:

    h = {}
    h[:z] = 1
    h[:b] = 2
    h[:a] = 3
    h[:x] = 0
    p h.keys     #=> [:z, :b, :a, :x]
    
    h.delete :b
    p h.keys     #=> [:z, :a, :x]
    
    h[:b] = 1
    p h.keys     #=> [:z, :a, :x, :b]
    
    因此,您可以为任何键设置任何值(如简单的
    true
    ),现在就有了一个有序集。您可以使用
    h.key?(obj)
    测试一个键,或者,如果您总是将每个键设置为具有真实值,则只需
    h[obj]
    。要拔出钥匙,请使用
    h.delete(obj)
    。要将有序集转换为数组,请使用
    h.keys

    由于当前恰好是基于散列构建的,因此当前可以将
    Set
    用作有序集。(例如,
    to_a
    方法的实现只是
    @hash.keys
    )但是,请注意,该库不能保证此行为,并且在将来可能会更改

    require 'set'
    s = Set[ :f, :o, :o, :b, :a, :r ]  #=> #<Set: {:f, :o, :b, :a, :r}>
    s << :z                            #=> #<Set: {:f, :o, :b, :a, :r, :z}>
    s.delete :o                        #=> #<Set: {:f, :b, :a, :r, :z}>
    s << :o                            #=> #<Set: {:f, :b, :a, :r, :z, :o}>
    s << :o                            #=> #<Set: {:f, :b, :a, :r, :z, :o}>
    s << :f                            #=> #<Set: {:f, :b, :a, :r, :z, :o}>
    s.to_a                             #=> [:f, :b, :a, :r, :z, :o]
    
    require'set'
    s=设置[:f,:o,:o,:b,:a,:r]#=>#
    #
    s、 删除:o#=>#
    #
    #
    #
    s、 到(a)=>[:f,:b,:a,:r,:z,:o]
    
    Insert不像数组版本那样处理变量参数,当使用范围或起始、长度版本并分配多个值时,您的[]=将允许重复(例如,arr[3..4]=[a,b]或arr[3,2]=[a,b])。坦率地说,我不确定Chris是否打算让其中任何一个起作用(重复是否否定了整个赋值/插入,或者仅仅否定了那个特定元素?),但只要他避免这些情况就可以了。此外,作为一般规则,我可能会委托给数组,而不是扩展,而是每个数组都是自己的。事实上,我不需要完整的数组功能,所以只需要Pesto:关于范围输入的好观点,我应该使用更简单但更慢的:def[]=(*args)super(*args)uniq!也结束,委托给数组?太正式了。我认为我已经通过扩展而不是像类数组那样打开数组来显示一些约束;定义。。。;结束;实际上,这被认为是最“rubyful”的方法,但它仍然给了我heebee-geebeesan其他继承问题是所有其他数组方法。例如,如果你添加两个唯一数组,那么你会得到一个(惊喜!)普通的旧数组。您可以
    undef_方法
    ,但数组包含许多实例方法,这是一个潜在的维护负担。我更喜欢一个较小的接口,其中所有方法都按照广告的方式工作(混合了可枚举和可比较的方法),而不是一个较大的继承接口,这可能会在将来困扰我。您可以在entry类中实现。也许是这样,当向容器中添加对象时,它会将递增的值存储到entry类的索引中。或者,您可以使用散列,将递增的值作为值输入,并将对象作为键。取回列表可能会比较慢(通过键访问会比较慢,但也有可能)。好主意。无需重新发明轮子。发送
    super
    时,是否要将参数传递给
    initialize
    on?@hdgarood调用
    super
    时,如果没有括号,它会自动传递当前方法中的所有参数。它很奇怪,不同于
    super()
    ——但很方便。