Set 類別

此函式庫提供 Set 類別,實作一個無序值集合,且沒有重複值。它結合了 Array 直覺的互操作功能和 Hash 快速查詢的功能。

to_set 方法已新增至 Enumerable 以供使用。

Set 容易與 Enumerable 物件(實作 each)一起使用。除了集合和陣列之外,大部分的初始化器方法和二元運算子都接受一般 Enumerable 物件。可以使用 to_set 方法將 Enumerable 物件轉換為 Set

Set 使用 Hash 作為儲存,因此您必須注意下列幾點

比較

比較運算子 <><=>= 實作為 {proper_,}{subset?,superset?} 方法的簡寫。<=> 運算子反映此順序,或傳回 nil 給兩個具有不同元素的集合(例如 {x, y}{x, z})。

範例

require 'set'
s1 = Set[1, 2]                        #=> #<Set: {1, 2}>
s2 = [1, 2].to_set                    #=> #<Set: {1, 2}>
s1 == s2                              #=> true
s1.add("foo")                         #=> #<Set: {1, 2, "foo"}>
s1.merge([2, 6])                      #=> #<Set: {1, 2, "foo", 6}>
s1.subset?(s2)                        #=> false
s2.subset?(s1)                        #=> true

聯絡

此處內容

首先,其他地方的內容。類別 Set

特別是,類別 Set 沒有許多用於擷取或反覆運算的方法。相反地,它依賴於 Enumerable 中的方法。

在此,類別 Set 提供對下列事項有用的方法

建立 Set 的方法

Set 運算的方法

比較的方法

查詢的方法

指定的方法

刪除方法

轉換方法

迭代方法

其他方法

常數

VERSION

公開類別方法

[](*ary) 按一下以切換來源

建立一個新的集合,包含指定的物件。

Set[1, 2]                   # => #<Set: {1, 2}>
Set[1, 2, 1]                # => #<Set: {1, 2}>
Set[1, 'c', :s]             # => #<Set: {1, "c", :s}>
# File lib/set.rb, line 228
def self.[](*ary)
  new(ary)
end
json_create(object) 按一下以切換來源

請參閱 as_json

# File ext/json/lib/json/add/set.rb, line 9
def self.json_create(object)
  new object['a']
end
new(enum = nil) { |o| ... } 按一下以切換來源

建立一個新的集合,包含指定可列舉物件的元素。

如果指定區塊,則 enum 的元素會由指定的區塊預先處理。

Set.new([1, 2])                       #=> #<Set: {1, 2}>
Set.new([1, 2, 1])                    #=> #<Set: {1, 2}>
Set.new([1, 'c', :s])                 #=> #<Set: {1, "c", :s}>
Set.new(1..5)                         #=> #<Set: {1, 2, 3, 4, 5}>
Set.new([1, 2, 3]) { |x| x * x }      #=> #<Set: {1, 4, 9}>
# File lib/set.rb, line 243
def initialize(enum = nil, &block) # :yields: o
  @hash ||= Hash.new(false)

  enum.nil? and return

  if block
    do_with_enum(enum) { |o| add(block[o]) }
  else
    merge(enum)
  end
end

公開執行個體方法

&(enum) 按一下以切換來源

傳回一個新的集合,包含集合和指定可列舉物件共有的元素。

Set[1, 3, 5] & Set[3, 2, 1]             #=> #<Set: {3, 1}>
Set['a', 'b', 'z'] & ['a', 'b', 'c']    #=> #<Set: {"a", "b"}>
# File lib/set.rb, line 640
def &(enum)
  n = self.class.new
  if enum.is_a?(Set)
    if enum.size > size
      each { |o| n.add(o) if enum.include?(o) }
    else
      enum.each { |o| n.add(o) if include?(o) }
    end
  else
    do_with_enum(enum) { |o| n.add(o) if include?(o) }
  end
  n
end
別名為: intersection
+(enum)
別名為: |
-(enum) 按一下以切換來源

傳回一個新的集合,透過複製集合建立,移除出現在指定可列舉物件中的每個元素。

Set[1, 3, 5] - Set[1, 5]                #=> #<Set: {3}>
Set['a', 'b', 'z'] - ['a', 'c']         #=> #<Set: {"b", "z"}>
# File lib/set.rb, line 630
def -(enum)
  dup.subtract(enum)
end
別名為: difference
<(set)
別名為: proper_subset?
<<(o)
別名為: add
<=(set)
別名為: subset?
<=>(set) 按一下以切換來源

如果集合相等,則傳回 0;如果集合是指定集合的真子集合/超集合,則傳回 -1/+1;如果兩個集合都有獨特的元素,則傳回 nil。

# File lib/set.rb, line 453
def <=>(set)
  return unless set.is_a?(Set)

  case size <=> set.size
  when -1 then -1 if proper_subset?(set)
  when +1 then +1 if proper_superset?(set)
  else 0 if self.==(set)
  end
end
==(other) 按一下以切換來源

如果兩個集合相等,則傳回 true。每個元素對的相等性是根據 Object#eql? 定義的。

Set[1, 2] == Set[2, 1]                       #=> true
Set[1, 3, 5] == Set[1, 5]                    #=> false
Set['a', 'b', 'c'] == Set['a', 'c', 'b']     #=> true
Set['a', 'b', 'c'] == ['a', 'c', 'b']        #=> false
# File lib/set.rb, line 674
def ==(other)
  if self.equal?(other)
    true
  elsif other.instance_of?(self.class)
    @hash == other.instance_variable_get(:@hash)
  elsif other.is_a?(Set) && self.size == other.size
    other.all? { |o| @hash.include?(o) }
  else
    false
  end
end
===(o)

如果指定的物件是集合的成員,則傳回 true;否則傳回 false。

用於 case 陳述式

require 'set'

case :apple
when Set[:potato, :carrot]
  "vegetable"
when Set[:apple, :banana]
  "fruit"
end
# => "fruit"

或單獨使用

Set[1, 2, 3] === 2   #=> true
Set[1, 2, 3] === 4   #=> false
別名為: include?
>(set)
別名為: proper_superset?
>=(set)
別名為: superset?
^(enum) 按一下以切換來源

傳回一個新的集合,包含集合和指定可列舉物件之間獨有的元素。(set ^ enum) 等於 ((set | enum) - (set & enum))

Set[1, 2] ^ Set[2, 3]                   #=> #<Set: {3, 1}>
Set[1, 'b', 'c'] ^ ['b', 'd']           #=> #<Set: {"d", 1, "c"}>
# File lib/set.rb, line 661
def ^(enum)
  n = Set.new(enum)
  each { |o| n.add(o) unless n.delete?(o) }
  n
end
add(o) 按一下以切換來源

將給定的物件加入集合並回傳自身。使用 merge 一次加入多個元素。

Set[1, 2].add(3)                    #=> #<Set: {1, 2, 3}>
Set[1, 2].add([3, 4])               #=> #<Set: {1, 2, [3, 4]}>
Set[1, 2].add(2)                    #=> #<Set: {1, 2}>
# File lib/set.rb, line 511
def add(o)
  @hash[o] = true
  self
end
別名為:<<
add?(o) 按一下切換來源

將給定的物件加入集合並回傳自身。如果物件已在集合中,則回傳 nil。

Set[1, 2].add?(3)                    #=> #<Set: {1, 2, 3}>
Set[1, 2].add?([3, 4])               #=> #<Set: {1, 2, [3, 4]}>
Set[1, 2].add?(2)                    #=> nil
# File lib/set.rb, line 523
def add?(o)
  add(o) unless include?(o)
end
as_json(*) 按一下切換來源

方法 Set#as_jsonSet.json_create 可用於序列化和反序列化 Set 物件;請參閱 Marshal

方法 Set#as_json 會序列化 self,回傳一個表示 self 的 2 元素雜湊。

require 'json/add/set'
x = Set.new(%w/foo bar baz/).as_json
# => {"json_class"=>"Set", "a"=>["foo", "bar", "baz"]}

方法 JSON.create 會反序列化此類雜湊,回傳一個 Set 物件。

Set.json_create(x) # => #<Set: {"foo", "bar", "baz"}>
# File ext/json/lib/json/add/set.rb, line 28
def as_json(*)
  {
    JSON.create_id => self.class.name,
    'a'            => to_a,
  }
end
classify() { |o| ... } 按一下切換來源

根據給定區塊的回傳值分類集合,並回傳一個 {值 => 元素集合} 成對的雜湊。區塊會對集合的每個元素呼叫一次,並將元素傳遞為參數。

require 'set'
files = Set.new(Dir.glob("*.rb"))
hash = files.classify { |f| File.mtime(f).year }
hash       #=> {2000=>#<Set: {"a.rb", "b.rb"}>,
           #    2001=>#<Set: {"c.rb", "d.rb", "e.rb"}>,
           #    2002=>#<Set: {"f.rb"}>}

如果未提供區塊,則回傳一個列舉器。

# File lib/set.rb, line 743
def classify # :yields: o
  block_given? or return enum_for(__method__) { size }

  h = {}

  each { |i|
    (h[yield(i)] ||= self.class.new).add(i)
  }

  h
end
clear() 按一下切換來源

移除所有元素並回傳自身。

set = Set[1, 'c', :s]             #=> #<Set: {1, "c", :s}>
set.clear                         #=> #<Set: {}>
set                               #=> #<Set: {}>
# File lib/set.rb, line 316
def clear
  @hash.clear
  self
end
collect!() { |o| ... } 按一下切換來源

使用 collect() 回傳的元素取代元素。如果未提供區塊,則回傳一個列舉器。

# File lib/set.rb, line 564
def collect!
  block_given? or return enum_for(__method__) { size }
  set = self.class.new
  each { |o| set << yield(o) }
  replace(set)
end
別名為:map!
compare_by_identity() 按一下切換來源

讓集合根據元素的身分進行比較,並回傳自身。此方法可能不受 Set 的所有子類別支援。

# File lib/set.rb, line 257
def compare_by_identity
  if @hash.respond_to?(:compare_by_identity)
    @hash.compare_by_identity
    self
  else
    raise NotImplementedError, "#{self.class.name}\##{__method__} is not implemented"
  end
end
compare_by_identity?() 按一下切換來源

如果集合將根據元素的身分進行比較,則回傳 true。另請參閱 Set#compare_by_identity

# File lib/set.rb, line 268
def compare_by_identity?
  @hash.respond_to?(:compare_by_identity?) && @hash.compare_by_identity?
end
delete(o) 按一下切換來源

從集合中刪除給定的物件並回傳自身。使用 subtract 一次刪除多個項目。

# File lib/set.rb, line 529
def delete(o)
  @hash.delete(o)
  self
end
delete?(o) 按一下以切換來源

從集合中刪除給定的物件並傳回自身。如果物件不在集合中,傳回 nil。

# File lib/set.rb, line 536
def delete?(o)
  delete(o) if include?(o)
end
delete_if() { |o| ... } 按一下以切換來源

刪除集合中區塊評估為 true 的每個元素,並傳回自身。如果未提供區塊,傳回列舉器。

# File lib/set.rb, line 543
def delete_if
  block_given? or return enum_for(__method__) { size }
  # @hash.delete_if should be faster, but using it breaks the order
  # of enumeration in subclasses.
  select { |o| yield o }.each { |o| @hash.delete(o) }
  self
end
difference(enum)
別名為:-
disjoint?(set) 按一下以切換來源

如果集合和給定的可列舉物件沒有共同元素,傳回 true。此方法與 intersect? 相反。

Set[1, 2, 3].disjoint? Set[3, 4]   #=> false
Set[1, 2, 3].disjoint? Set[4, 5]   #=> true
Set[1, 2, 3].disjoint? [3, 4]      #=> false
Set[1, 2, 3].disjoint? 4..5        #=> true
# File lib/set.rb, line 492
def disjoint?(set)
  !intersect?(set)
end
divide(&func) 按一下以切換來源

根據給定區塊定義的共性,將集合分割成一組子集合。

如果區塊的元數為 2,則元素 o1 和 o2 在區塊呼叫 (block.call(o1, o2)) 為 true 時為共用。否則,如果區塊呼叫 (block.call(o1)) == 區塊呼叫 (block.call(o2)),則元素 o1 和 o2 為共用。

require 'set'
numbers = Set[1, 3, 4, 6, 9, 10, 11]
set = numbers.divide { |i,j| (i - j).abs == 1 }
set        #=> #<Set: {#<Set: {1}>,
           #           #<Set: {11, 9, 10}>,
           #           #<Set: {3, 4}>,
           #           #<Set: {6}>}>

如果未提供區塊,則回傳一個列舉器。

# File lib/set.rb, line 771
def divide(&func)
  func or return enum_for(__method__) { size }

  if func.arity == 2
    require 'tsort'

    class << dig = {}         # :nodoc:
      include TSort

      alias tsort_each_node each_key
      def tsort_each_child(node, &block)
        fetch(node).each(&block)
      end
    end

    each { |u|
      dig[u] = a = []
      each{ |v| func.call(u, v) and a << v }
    }

    set = Set.new()
    dig.each_strongly_connected_component { |css|
      set.add(self.class.new(css))
    }
    set
  else
    Set.new(classify(&func).values)
  end
end
each(&block) 按一下以切換來源

對集合中的每個元素呼叫給定的區塊一次,將元素作為參數傳遞。如果未提供區塊,傳回列舉器。

# File lib/set.rb, line 499
def each(&block)
  block_given? or return enum_for(__method__) { size }
  @hash.each_key(&block)
  self
end
empty?() 按一下以切換來源

如果集合不包含任何元素,傳回 true。

# File lib/set.rb, line 307
def empty?
  @hash.empty?
end
filter!(&block)

等於 Set#select!

別名為:select!
flatten() 按一下以切換來源

傳回一個新的集合,為集合的副本,遞迴式地平坦化每個包含的集合。

# File lib/set.rb, line 377
def flatten
  self.class.new.flatten_merge(self)
end
flatten!() 按一下以切換來源

等於 Set#flatten,但會將接收器取代為結果。如果未進行任何修改,傳回 nil。

# File lib/set.rb, line 383
def flatten!
  replace(flatten()) if any?(Set)
end
include?(o) 按一下以切換來源

如果集合包含指定的物件,則傳回 true。

請注意,include?member? 不同於其他可列舉物件,它們不會使用 == 來測試成員相等性。

另請參閱 Enumerable#include?

# File lib/set.rb, line 393
def include?(o)
  @hash[o]
end
別名: member?===
initialize_clone(orig, **options) 按一下以切換來源

複製內部雜湊。

呼叫超類別方法
# File lib/set.rb, line 290
def initialize_clone(orig, **options)
  super
  @hash = orig.instance_variable_get(:@hash).clone(**options)
end
initialize_dup(orig) 按一下以切換來源

複製內部雜湊。

呼叫超類別方法
# File lib/set.rb, line 284
def initialize_dup(orig)
  super
  @hash = orig.instance_variable_get(:@hash).dup
end
inspect() 按一下以切換來源

傳回包含集合人類可讀表示形式的字串(“#<Set: {element1, element2, …}>”)。

# File lib/set.rb, line 811
def inspect
  ids = (Thread.current[InspectKey] ||= [])

  if ids.include?(object_id)
    return sprintf('#<%s: {...}>', self.class.name)
  end

  ids << object_id
  begin
    return sprintf('#<%s: {%s}>', self.class, to_a.inspect[1..-2])
  ensure
    ids.pop
  end
end
別名: to_s
intersect?(set) 按一下以切換來源

如果集合和指定的可列舉物件至少有一個共同元素,則傳回 true。

Set[1, 2, 3].intersect? Set[4, 5]   #=> false
Set[1, 2, 3].intersect? Set[3, 4]   #=> true
Set[1, 2, 3].intersect? 4..5        #=> false
Set[1, 2, 3].intersect? [3, 4]      #=> true
# File lib/set.rb, line 470
def intersect?(set)
  case set
  when Set
    if size < set.size
      any?(set)
    else
      set.any?(self)
    end
  when Enumerable
    set.any?(self)
  else
    raise ArgumentError, "value must be enumerable"
  end
end
intersection(enum)
別名: &
join(separator=nil) 按一下以切換來源

傳回透過將集合的每個元素轉換為字串所建立的字串。另請參閱: Array#join

# File lib/set.rb, line 803
def join(separator=nil)
  to_a.join(separator)
end
keep_if() { |o| ... } 按一下以切換來源

刪除集合中區塊評估為 false 的每個元素,並傳回 self。如果未提供區塊,則傳回列舉器。

# File lib/set.rb, line 554
def keep_if
  block_given? or return enum_for(__method__) { size }
  # @hash.keep_if should be faster, but using it breaks the order of
  # enumeration in subclasses.
  reject { |o| yield o }.each { |o| @hash.delete(o) }
  self
end
length()
別名: size
map!()
別名: collect!
member?(o)
別名為: include?
merge(*enums, **nil) 按一下以切換來源

將指定可列舉物件的元素合併到集合中,並傳回 self。

# File lib/set.rb, line 595
def merge(*enums, **nil)
  enums.each do |enum|
    if enum.instance_of?(self.class)
      @hash.update(enum.instance_variable_get(:@hash))
    else
      do_with_enum(enum) { |o| add(o) }
    end
  end

  self
end
proper_subset?(set) 按一下以切換來源

如果集合是指定集合的真子集合,則傳回 true。

# File lib/set.rb, line 438
def proper_subset?(set)
  case
  when set.instance_of?(self.class) && @hash.respond_to?(:<)
    @hash < set.instance_variable_get(:@hash)
  when set.is_a?(Set)
    size < set.size && all?(set)
  else
    raise ArgumentError, "value must be a set"
  end
end
別名: <
proper_superset?(set) 按一下以切換來源

如果集合是指定集合的真超集合,則傳回 true。

# File lib/set.rb, line 412
def proper_superset?(set)
  case
  when set.instance_of?(self.class) && @hash.respond_to?(:>)
    @hash > set.instance_variable_get(:@hash)
  when set.is_a?(Set)
    size > set.size && set.all?(self)
  else
    raise ArgumentError, "value must be a set"
  end
end
別名: >
reject!(&block) 按一下以切換來源

等同於 Set#delete_if,但如果沒有任何變更,則會傳回 nil。如果未提供區塊,則會傳回一個列舉器。

# File lib/set.rb, line 574
def reject!(&block)
  block_given? or return enum_for(__method__) { size }
  n = size
  delete_if(&block)
  self if size != n
end
replace(enum) 按一下以切換來源

使用給定的可列舉物件的內容取代集合的內容,並傳回 self。

set = Set[1, 'c', :s]             #=> #<Set: {1, "c", :s}>
set.replace([1, 2])               #=> #<Set: {1, 2}>
set                               #=> #<Set: {1, 2}>
# File lib/set.rb, line 327
def replace(enum)
  if enum.instance_of?(self.class)
    @hash.replace(enum.instance_variable_get(:@hash))
    self
  else
    do_with_enum(enum)  # make sure enum is enumerable before calling clear
    clear
    merge(enum)
  end
end
reset() 按一下以切換來源

在修改現有元素後重設內部狀態,並傳回 self。

元素將會重新編製索引並去重。

# File lib/set.rb, line 699
def reset
  if @hash.respond_to?(:rehash)
    @hash.rehash # This should perform frozenness check.
  else
    raise FrozenError, "can't modify frozen #{self.class.name}" if frozen?
  end
  self
end
select!(&block) 按一下以切換來源

等同於 Set#keep_if,但如果沒有任何變更,則會傳回 nil。如果未提供區塊,則會傳回一個列舉器。

# File lib/set.rb, line 583
def select!(&block)
  block_given? or return enum_for(__method__) { size }
  n = size
  keep_if(&block)
  self if size != n
end
別名為: filter!
size() 按一下以切換來源

傳回元素的數量。

# File lib/set.rb, line 301
def size
  @hash.size
end
別名為: length
subset?(set) 按一下以切換來源

如果集合是給定集合的子集合,則傳回 true。

# File lib/set.rb, line 425
def subset?(set)
  case
  when set.instance_of?(self.class) && @hash.respond_to?(:<=)
    @hash <= set.instance_variable_get(:@hash)
  when set.is_a?(Set)
    size <= set.size && all?(set)
  else
    raise ArgumentError, "value must be a set"
  end
end
別名為: <=
subtract(enum) 按一下以切換來源

刪除出現在給定可列舉物件中的每個元素,並傳回 self。

# File lib/set.rb, line 609
def subtract(enum)
  do_with_enum(enum) { |o| delete(o) }
  self
end
superset?(set) 按一下以切換來源

如果集合是給定集合的超集合,則傳回 true。

# File lib/set.rb, line 399
def superset?(set)
  case
  when set.instance_of?(self.class) && @hash.respond_to?(:>=)
    @hash >= set.instance_variable_get(:@hash)
  when set.is_a?(Set)
    size >= set.size && set.all?(self)
  else
    raise ArgumentError, "value must be a set"
  end
end
別名為: >=
to_a() 按一下以切換來源

將集合轉換為陣列。元素的順序不確定。

Set[1, 2].to_a                    #=> [1, 2]
Set[1, 'c', :s].to_a              #=> [1, "c", :s]
# File lib/set.rb, line 342
def to_a
  @hash.keys
end
to_json(*args) 按一下以切換來源

傳回代表 selfJSON 字串

require 'json/add/set'
puts Set.new(%w/foo bar baz/).to_json

輸出

{"json_class":"Set","a":["foo","bar","baz"]}
# File ext/json/lib/json/add/set.rb, line 44
def to_json(*args)
  as_json.to_json(*args)
end
to_s()
別名為: inspect
to_set(klass = Set, *args, &block) 按一下以切換來源

如果沒有給定引數,則傳回 self。否則,使用 klass.new(self, *args, &block) 將集合轉換為另一個集合。

在子類別中,傳回 klass.new(self, *args, &block),除非覆寫。

# File lib/set.rb, line 351
def to_set(klass = Set, *args, &block)
  return self if instance_of?(Set) && klass == Set && block.nil? && args.empty?
  klass.new(self, *args, &block)
end
union(enum)
別名為: |
|(enum) 按一下以切換來源

傳回一個新的集合,該集合是透過合併集合和給定可列舉物件的元素而建立的。

Set[1, 2, 3] | Set[2, 4, 5]         #=> #<Set: {1, 2, 3, 4, 5}>
Set[1, 5, 'z'] | (1..6)             #=> #<Set: {1, 5, "z", 2, 3, 4, 6}>
# File lib/set.rb, line 619
def |(enum)
  dup.merge(enum)
end
別名為:+union