10

...または、重複エントリを防ぐ配列。

Rubyには次のようなオブジェクトがありますか?

  • []、[] =、<<に応答します
  • 重複するエントリをサイレントにドロップします
  • 列挙可能です(または少なくともfind_allをサポートします)
  • エントリが挿入された順序を保持します

私の知る限り、配列はポイント1、3、4をサポートしています。セットは1、2、3をサポートします(4はサポートしません)。そして、私のエントリは<=>を実装していないため、SortedSetは機能しません。

4

5 に答える 5

13

Ruby 1.9以降、組み込みHashオブジェクトは挿入順序を保持します。例えば:

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]

したがって、任意のキーに任意の値(simpleなどtrue)を設定でき、順序セットが作成されます。いずれかを使用してキーをテストできますh.key?(obj)。または、常に各キーを真の値に設定する場合は、を使用しますh[obj]。キーを削除するには、を使用しますh.delete(obj)。順序集合を配列に変換するには、を使用しますh.keys

現在、Ruby 1.9Setライブラリ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]
于 2013-01-22T21:47:13.510 に答える
7

私の知る限りではありません。その数学的性質によるSetは、順序付けされていないことを意味します(または、少なくとも実装上、順序を保証しないことを意味します。実際、通常はハッシュテーブルとして実装されるため、順序が乱れます。 )。

ただし、これを行うために、配列を直接拡張するか、サブクラス化することは難しくありません。私はそれを試してみましたが、これは機能します:

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

すべての拠点をカバーしているようです。OReillyの便利なRubyCookbookを参照として使用しました。これらには、「ソートされた配列がソートされたままであることを確認する」ためのレシピがあります。

于 2009-04-21T18:25:08.523 に答える
6

active_supportのOrderedHashが必要ですが、私はこのソリューションが好きです

require 'active_support/ordered_hash'

class OrderedSet < Set

  def initialize enum = nil, &block
    @hash = ActiveSupport::OrderedHash.new
    super
  end

end

=)

于 2011-12-09T20:56:32.947 に答える
1

ハッシュを使用して値を格納し、各ハッシュペアの値に増分値を格納することができます。次に、値を介してオブジェクトにアクセスすることにより、ゆっくりではありますが、ソートされた方法でセットにアクセスできます。

さらに説明するために、後でここにいくつかのコードを追加しようとします。

値を介したアクセスは、キーによるアクセスよりもはるかに遅いことを認識しています。

更新1:Ruby 1.9では、ハッシュ要素は挿入順序で繰り返されます。

于 2009-04-21T22:57:34.670 に答える
0

私が知っていることではありませんが、自分でロールするのは難しいことではありません。Arrayをサブクラス化し、Setを使用して一意性の制約を維持するだけです。

サイレントドロップに関する1つの質問。これは#[] =にどのように影響しますか?既存のエントリをすでに他の場所に保存されているもので上書きしようとした場合、とにかく削除される要素を削除する必要がありますか?どちらの方法でも、将来的に厄介な驚きをもたらす可能性があると思います。

于 2009-04-21T18:24:33.050 に答える