3 # set.rb - defines the Set class
5 # Copyright (c) 2002 Akinori MUSHA <knu@iDaemons.org>
7 # Documentation by Akinori MUSHA and Gavin Sinclair.
9 # All rights reserved. You can redistribute and/or modify it under the same
12 # $Id: set.rb 11980 2007-03-03 16:06:45Z knu $
16 # This library provides the Set class, which deals with a collection
17 # of unordered values with no duplicates. It is a hybrid of Array's
18 # intuitive inter-operation facilities and Hash's fast lookup. If you
19 # need to keep values ordered, use the SortedSet class.
21 # The method +to_set+ is added to Enumerable for convenience.
23 # See the Set class for an example of usage.
27 # Set implements a collection of unordered values with no duplicates.
28 # This is a hybrid of Array's intuitive inter-operation facilities and
31 # Several methods accept any Enumerable object (implementing +each+)
32 # for greater flexibility: new, replace, merge, subtract, |, &, -, ^.
34 # The equality of each couple of elements is determined according to
35 # Object#eql? and Object#hash, since Set uses Hash as storage.
37 # Finally, if you are using class Set, you can also use Enumerable#to_set
43 # s1 = Set.new [1, 2] # -> #<Set: {1, 2}>
44 # s2 = [1, 2].to_set # -> #<Set: {1, 2}>
46 # s1.add("foo") # -> #<Set: {1, 2, "foo"}>
47 # s1.merge([2, 6]) # -> #<Set: {6, 1, 2, "foo"}>
48 # s1.subset? s2 # -> false
49 # s2.subset? s1 # -> true
54 # Creates a new set containing the given objects.
59 # Creates a new set containing the elements of the given enumerable
62 # If a block is given, the elements of enum are preprocessed by the
64 def initialize(enum = nil, &block) # :yields: o
70 enum.each { |o| add(block[o]) }
77 def initialize_copy(orig)
78 @hash = orig.instance_eval{@hash}.dup
81 # Returns the number of elements.
87 # Returns true if the set contains no elements.
92 # Removes all elements and returns self.
98 # Replaces the contents of the set with the contents of the given
99 # enumerable object and returns self.
101 if enum.class == self.class
102 @hash.replace(enum.instance_eval { @hash })
104 enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
106 enum.each { |o| add(o) }
112 # Converts the set to an array. The order of elements is uncertain.
117 def flatten_merge(set, seen = Set.new)
120 if seen.include?(e_id = e.object_id)
121 raise ArgumentError, "tried to flatten recursive Set"
125 flatten_merge(e, seen)
134 protected :flatten_merge
136 # Returns a new set that is a copy of the set, flattening each
137 # containing set recursively.
139 self.class.new.flatten_merge(self)
142 # Equivalent to Set#flatten, but replaces the receiver with the
143 # result in place. Returns nil if no modifications were made.
145 if detect { |e| e.is_a?(Set) }
152 # Returns true if the set contains the given object.
156 alias member? include?
158 # Returns true if the set is a superset of the given set.
160 set.is_a?(Set) or raise ArgumentError, "value must be a set"
161 return false if size < set.size
162 set.all? { |o| include?(o) }
165 # Returns true if the set is a proper superset of the given set.
166 def proper_superset?(set)
167 set.is_a?(Set) or raise ArgumentError, "value must be a set"
168 return false if size <= set.size
169 set.all? { |o| include?(o) }
172 # Returns true if the set is a subset of the given set.
174 set.is_a?(Set) or raise ArgumentError, "value must be a set"
175 return false if set.size < size
176 all? { |o| set.include?(o) }
179 # Returns true if the set is a proper subset of the given set.
180 def proper_subset?(set)
181 set.is_a?(Set) or raise ArgumentError, "value must be a set"
182 return false if set.size <= size
183 all? { |o| set.include?(o) }
186 # Calls the given block once for each element in the set, passing
187 # the element as parameter.
189 @hash.each_key { |o| yield(o) }
193 # Adds the given object to the set and returns self. Use +merge+ to
194 # add several elements at once.
201 # Adds the given object to the set and returns self. If the
202 # object is already in the set, returns nil.
211 # Deletes the given object from the set and returns self. Use +subtract+ to
212 # delete several items at once.
218 # Deletes the given object from the set and returns self. If the
219 # object is not in the set, returns nil.
228 # Deletes every element of the set for which block evaluates to
229 # true, and returns self.
231 @hash.delete_if { |o,| yield(o) }
235 # Do collect() destructively.
238 each { |o| set << yield(o) }
243 # Equivalent to Set#delete_if, but returns nil if no changes were
247 delete_if { |o| yield(o) }
248 size == n ? nil : self
251 # Merges the elements of the given enumerable object to the set and
255 @hash.update(enum.instance_eval { @hash })
257 enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
258 enum.each { |o| add(o) }
264 # Deletes every element that appears in the given enumerable object
267 enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
268 enum.each { |o| delete(o) }
272 # Returns a new set built by merging the set and the elements of the
273 # given enumerable object.
275 enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
281 # Returns a new set built by duplicating the set, removing every
282 # element that appears in the given enumerable object.
284 enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
287 alias difference - ##
289 # Returns a new set containing elements common to the set and the
290 # given enumerable object.
292 enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
294 enum.each { |o| n.add(o) if include?(o) }
297 alias intersection & ##
299 # Returns a new set containing elements exclusive between the set
300 # and the given enumerable object. (set ^ enum) is equivalent to
301 # ((set | enum) - (set & enum)).
303 enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
305 each { |o| if n.include?(o) then n.delete(o) else n.add(o) end }
309 # Returns true if two sets are equal. The equality of each couple
310 # of elements is defined according to Object#eql?.
312 equal?(set) and return true
314 set.is_a?(Set) && size == set.size or return false
317 set.all? { |o| hash.include?(o) }
324 def eql?(o) # :nodoc:
325 return false unless o.is_a?(Set)
326 @hash.eql?(o.instance_eval{@hash})
329 # Classifies the set by the return value of the given block and
330 # returns a hash of {value => set of elements} pairs. The block is
331 # called once for each element of the set, passing the element as
337 # files = Set.new(Dir.glob("*.rb"))
338 # hash = files.classify { |f| File.mtime(f).year }
339 # p hash # => {2000=>#<Set: {"a.rb", "b.rb"}>,
340 # # 2001=>#<Set: {"c.rb", "d.rb", "e.rb"}>,
341 # # 2002=>#<Set: {"f.rb"}>}
342 def classify # :yields: o
347 (h[x] ||= self.class.new).add(i)
353 # Divides the set into a set of subsets according to the commonality
354 # defined by the given block.
356 # If the arity of the block is 2, elements o1 and o2 are in common
357 # if block.call(o1, o2) is true. Otherwise, elements o1 and o2 are
358 # in common if block.call(o1) == block.call(o2).
363 # numbers = Set[1, 3, 4, 6, 9, 10, 11]
364 # set = numbers.divide { |i,j| (i - j).abs == 1 }
365 # p set # => #<Set: {#<Set: {1}>,
366 # # #<Set: {11, 9, 10}>,
373 class << dig = {} # :nodoc:
376 alias tsort_each_node each_key
377 def tsort_each_child(node, &block)
378 fetch(node).each(&block)
384 each{ |v| func.call(u, v) and a << v }
388 dig.each_strongly_connected_component { |css|
389 set.add(self.class.new(css))
393 Set.new(classify(&func).values)
397 InspectKey = :__inspect_key__ # :nodoc:
399 # Returns a string containing a human-readable representation of the
400 # set. ("#<Set: {element1, element2, ...}>")
402 ids = (Thread.current[InspectKey] ||= [])
404 if ids.include?(object_id)
405 return sprintf('#<%s: {...}>', self.class.name)
410 return sprintf('#<%s: {%s}>', self.class, to_a.inspect[1..-2])
416 def pretty_print(pp) # :nodoc:
417 pp.text sprintf('#<%s: {', self.class.name)
419 pp.seplist(self) { |o|
426 def pretty_print_cycle(pp) # :nodoc:
427 pp.text sprintf('#<%s: {%s}>', self.class.name, empty? ? '' : '...')
431 # SortedSet implements a set which elements are sorted in order. See Set.
432 class SortedSet < Set
436 def [](*ary) # :nodoc:
444 # a hack to shut up warning
445 alias old_init initialize
446 remove_method :old_init
452 def initialize(*args, &block)
459 def initialize(*args, &block)
489 @hash.delete_if { |o,| yield(o) }
490 @keys = nil if @hash.size != n
500 to_a.each { |o| yield(o) }
504 (@keys = @hash.keys).sort! unless @keys
514 def initialize(*args, &block) # :nodoc:
516 initialize(*args, &block)
521 # Makes a set from the enumerable object with given arguments.
522 # Needs to +require "set"+ to use this method.
523 def to_set(klass = Set, *args, &block)
524 klass.new(self, *args, &block)
529 # == RestricedSet class
530 # RestricedSet implements a set with restrictions defined by a given
537 # --- RestricedSet::new(enum = nil) { |o| ... }
538 # --- RestricedSet::new(enum = nil) { |rset, o| ... }
539 # Creates a new restricted set containing the elements of the given
540 # enumerable object. Restrictions are defined by the given block.
542 # If the block's arity is 2, it is called with the RestrictedSet
543 # itself and an object to see if the object is allowed to be put in
546 # Otherwise, the block is called with an object to see if the object
547 # is allowed to be put in the set.
549 # === Instance Methods
550 # --- restriction_proc
551 # Returns the restriction procedure of the set.
555 # class RestricedSet < Set
556 # def initialize(*args, &block)
557 # @proc = block or raise ArgumentError, "missing a block"
559 # if @proc.arity == 2
562 # @hash[o] = true if @proc.call(self, o)
568 # if include?(o) || !@proc.call(self, o)
577 # enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
579 # enum.each { |o| add(o) }
585 # enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
586 # enum.each { |o| add(o) }
602 # if include?(o) || !@proc.call(o)
615 # def restriction_proc
621 eval DATA.read, nil, $0, __LINE__+4
628 class TC_Set < Test::Unit::TestCase
630 assert_nothing_raised {
636 assert_equal(0, Set[].size)
637 assert_equal(1, Set[nil].size)
638 assert_equal(1, Set[[]].size)
639 assert_equal(1, Set[[nil]].size)
642 assert_equal(Set.new([2,4,6]), set)
646 assert_nothing_raised {
654 assert_raises(ArgumentError) {
657 assert_raises(ArgumentError) {
660 assert_raises(ArgumentError) {
664 assert_equal(0, Set.new().size)
665 assert_equal(0, Set.new(nil).size)
666 assert_equal(0, Set.new([]).size)
667 assert_equal(1, Set.new([nil]).size)
672 assert_equal(false, set.empty?)
673 assert_equal(3, set.size)
677 s = Set.new(ary) { |o| o * 2 }
678 assert_equal([2,4,6], s.sort)
685 assert_equal(Set.new, set2)
692 assert_not_same(set1, set2)
694 assert_equal(set1, set2)
698 assert_not_equal(set1, set2)
702 assert_equal(0, Set[].size)
703 assert_equal(2, Set[1,2].size)
704 assert_equal(2, Set[1,2,1].size)
708 assert_equal(true, Set[].empty?)
709 assert_equal(false, Set[1, 2].empty?)
716 assert_same(set, ret)
717 assert_equal(true, set.empty?)
722 ret = set.replace('a'..'c')
724 assert_same(set, ret)
725 assert_equal(Set['a','b','c'], set)
732 assert_equal([1,2,3], ary.sort)
754 assert_not_same(set2, set1)
755 assert_equal(set3, set2)
761 assert_same(orig_set1, set1)
762 assert_equal(set3, set1)
764 # test3; multiple occurrences of a set in an set
766 set2 = Set[set1, Set[set1, 4], 3]
768 assert_nothing_raised {
772 assert_equal(Set.new(1..4), set2)
779 assert_raises(ArgumentError) {
783 # test5; miscellaneous
785 set = Set[Set[empty, "a"],Set[empty, "b"]]
787 assert_nothing_raised {
791 set1 = empty.merge(Set["no_more", set])
793 assert_nil(Set.new(0..31).flatten!)
795 x = Set[Set[],Set[1,2]].flatten!
804 assert_equal(true, set.include?(1))
805 assert_equal(true, set.include?(2))
806 assert_equal(true, set.include?(3))
807 assert_equal(false, set.include?(0))
808 assert_equal(false, set.include?(nil))
810 set = Set["1",nil,"2",nil,"0","1",false]
811 assert_equal(true, set.include?(nil))
812 assert_equal(true, set.include?(false))
813 assert_equal(true, set.include?("1"))
814 assert_equal(false, set.include?(0))
815 assert_equal(false, set.include?(true))
821 assert_raises(ArgumentError) {
825 assert_raises(ArgumentError) {
829 assert_raises(ArgumentError) {
833 assert_equal(true, set.superset?(Set[]))
834 assert_equal(true, set.superset?(Set[1,2]))
835 assert_equal(true, set.superset?(Set[1,2,3]))
836 assert_equal(false, set.superset?(Set[1,2,3,4]))
837 assert_equal(false, set.superset?(Set[1,4]))
839 assert_equal(true, Set[].superset?(Set[]))
842 def test_proper_superset?
845 assert_raises(ArgumentError) {
846 set.proper_superset?()
849 assert_raises(ArgumentError) {
850 set.proper_superset?(2)
853 assert_raises(ArgumentError) {
854 set.proper_superset?([2])
857 assert_equal(true, set.proper_superset?(Set[]))
858 assert_equal(true, set.proper_superset?(Set[1,2]))
859 assert_equal(false, set.proper_superset?(Set[1,2,3]))
860 assert_equal(false, set.proper_superset?(Set[1,2,3,4]))
861 assert_equal(false, set.proper_superset?(Set[1,4]))
863 assert_equal(false, Set[].proper_superset?(Set[]))
869 assert_raises(ArgumentError) {
873 assert_raises(ArgumentError) {
877 assert_raises(ArgumentError) {
881 assert_equal(true, set.subset?(Set[1,2,3,4]))
882 assert_equal(true, set.subset?(Set[1,2,3]))
883 assert_equal(false, set.subset?(Set[1,2]))
884 assert_equal(false, set.subset?(Set[]))
886 assert_equal(true, Set[].subset?(Set[1]))
887 assert_equal(true, Set[].subset?(Set[]))
890 def test_proper_subset?
893 assert_raises(ArgumentError) {
897 assert_raises(ArgumentError) {
898 set.proper_subset?(2)
901 assert_raises(ArgumentError) {
902 set.proper_subset?([2])
905 assert_equal(true, set.proper_subset?(Set[1,2,3,4]))
906 assert_equal(false, set.proper_subset?(Set[1,2,3]))
907 assert_equal(false, set.proper_subset?(Set[1,2]))
908 assert_equal(false, set.proper_subset?(Set[]))
910 assert_equal(false, Set[].proper_subset?(Set[]))
914 ary = [1,3,5,7,10,20]
917 assert_raises(LocalJumpError) {
921 assert_nothing_raised {
923 ary.delete(o) or raise "unexpected element: #{o}"
926 ary.empty? or raise "forgotten elements: #{ary.join(', ')}"
934 assert_same(set, ret)
935 assert_equal(Set[1,2,3], set)
939 assert_equal(Set[1,2,3], set)
942 assert_same(set, ret)
943 assert_equal(Set[1,2,3,4], set)
946 assert_same(set, ret)
947 assert_equal(Set[1,2,3,4,5], set)
954 assert_same(set, ret)
955 assert_equal(Set[1,2,3], set)
959 assert_equal(Set[1,2,3], set)
962 assert_equal(set, ret)
963 assert_equal(Set[1,3], set)
966 assert_equal(set, ret)
967 assert_equal(Set[3], set)
972 ret = set.delete_if { |i| i > 10 }
973 assert_same(set, ret)
974 assert_equal(Set.new(1..10), set)
977 ret = set.delete_if { |i| i % 3 == 0 }
978 assert_same(set, ret)
979 assert_equal(Set[1,2,4,5,7,8,10], set)
983 set = Set[1,2,3,'a','b','c',-1..1,2..4]
985 ret = set.collect! { |i|
996 assert_same(set, ret)
997 assert_equal(Set[2,4,6,'A','B','C',nil], set)
1001 set = Set.new(1..10)
1003 ret = set.reject! { |i| i > 10 }
1005 assert_equal(Set.new(1..10), set)
1007 ret = set.reject! { |i| i % 3 == 0 }
1008 assert_same(set, ret)
1009 assert_equal(Set[1,2,4,5,7,8,10], set)
1015 ret = set.merge([2,4,6])
1016 assert_same(set, ret)
1017 assert_equal(Set[1,2,3,4,6], set)
1023 ret = set.subtract([2,4,6])
1024 assert_same(set, ret)
1025 assert_equal(Set[1,3], set)
1032 assert_not_same(set, ret)
1033 assert_equal(Set[1,2,3,4,6], ret)
1040 assert_not_same(set, ret)
1041 assert_equal(Set[1,3], ret)
1048 assert_not_same(set, ret)
1049 assert_equal(Set[2,4], ret)
1054 ret = set ^ [2,4,5,5]
1055 assert_not_same(set, ret)
1056 assert_equal(Set[1,3,5], ret)
1063 assert_equal(set1, set1)
1064 assert_equal(set1, set2)
1065 assert_not_equal(Set[1], [1])
1067 set1 = Class.new(Set)["a", "b"]
1068 set2 = Set["a", "b", set1]
1069 set1 = set1.add(set1.clone)
1071 # assert_equal(set1, set2)
1072 # assert_equal(set2, set1)
1073 assert_equal(set2, set2.clone)
1074 assert_equal(set1.clone, set1)
1076 assert_not_equal(Set[Exception.new,nil], Set[Exception.new,Exception.new], "[ruby-dev:26127]")
1086 set = Set.new(1..10)
1087 ret = set.classify { |i| i % 3 }
1089 assert_equal(3, ret.size)
1090 assert_instance_of(Hash, ret)
1091 ret.each_value { |value| assert_instance_of(Set, value) }
1092 assert_equal(Set[3,6,9], ret[0])
1093 assert_equal(Set[1,4,7,10], ret[1])
1094 assert_equal(Set[2,5,8], ret[2])
1098 set = Set.new(1..10)
1099 ret = set.divide { |i| i % 3 }
1101 assert_equal(3, ret.size)
1103 ret.each { |s| n += s.size }
1104 assert_equal(set.size, n)
1105 assert_equal(set, ret.flatten)
1107 set = Set[7,10,5,11,1,3,4,9,0]
1108 ret = set.divide { |a,b| (a - b).abs == 1 }
1110 assert_equal(4, ret.size)
1112 ret.each { |s| n += s.size }
1113 assert_equal(set.size, n)
1114 assert_equal(set, ret.flatten)
1117 assert_equal(Set[0,1], s)
1119 assert_equal(Set[3,4,5], s)
1121 assert_equal(Set[7], s)
1123 assert_equal(Set[9,10,11], s)
1125 raise "unexpected group: #{s.inspect}"
1133 assert_equal('#<Set: {1}>', set1.inspect)
1135 set2 = Set[Set[0], 1, 2, set1]
1136 assert_equal(false, set2.inspect.include?('#<Set: {...}>'))
1139 assert_equal(true, set1.inspect.include?('#<Set: {...}>'))
1142 # def test_pretty_print
1145 # def test_pretty_print_cycle
1149 class TC_SortedSet < Test::Unit::TestCase
1151 s = SortedSet[4,5,3,1,2]
1153 assert_equal([1,2,3,4,5], s.to_a)
1156 s.each { |o| assert(prev < o) if prev; prev = o }
1157 assert_not_nil(prev)
1159 s.map! { |o| -2 * o }
1161 assert_equal([-10,-8,-6,-4,-2], s.to_a)
1164 s.each { |o| assert(prev < o) if prev; prev = o }
1165 assert_not_nil(prev)
1167 s = SortedSet.new([2,1,3]) { |o| o * -2 }
1168 assert_equal([-6,-4,-2], s.to_a)
1172 class TC_Enumerable < Test::Unit::TestCase
1174 ary = [2,5,4,3,2,1,3]
1177 assert_instance_of(Set, set)
1178 assert_equal([1,2,3,4,5], set.sort)
1180 set = ary.to_set { |o| o * -2 }
1181 assert_instance_of(Set, set)
1182 assert_equal([-10,-8,-6,-4,-2], set.sort)
1184 set = ary.to_set(SortedSet)
1185 assert_instance_of(SortedSet, set)
1186 assert_equal([1,2,3,4,5], set.to_a)
1188 set = ary.to_set(SortedSet) { |o| o * -2 }
1189 assert_instance_of(SortedSet, set)
1190 assert_equal([-10,-8,-6,-4,-2], set.sort)
1194 # class TC_RestricedSet < Test::Unit::TestCase
1196 # assert_raises(ArgumentError) { RestricedSet.new }
1198 # s = RestricedSet.new([-1,2,3]) { |o| o > 0 }
1199 # assert_equal([2,3], s.sort)
1202 # def test_restriction_proc
1203 # s = RestricedSet.new([-1,2,3]) { |o| o > 0 }
1205 # f = s.restriction_proc
1206 # assert_instance_of(Proc, f)
1212 # s = RestricedSet.new(-3..3) { |o| o > 0 }
1213 # assert_equal([1,2,3], s.sort)
1215 # s.replace([-2,0,3,4,5])
1216 # assert_equal([3,4,5], s.sort)
1220 # s = RestricedSet.new { |o| o > 0 }
1222 # assert_equal([1,2,3,4,5], s.sort)
1224 # s.merge([10,-10,-8,8])
1225 # assert_equal([1,2,3,4,5,8,10], s.sort)