diff options
Diffstat (limited to 'lib/set.rb')
| -rw-r--r-- | lib/set.rb | 778 |
1 files changed, 0 insertions, 778 deletions
diff --git a/lib/set.rb b/lib/set.rb deleted file mode 100644 index 1dcfbfcdef..0000000000 --- a/lib/set.rb +++ /dev/null @@ -1,778 +0,0 @@ -#!/usr/bin/env ruby -# -# set - defines the Set class -# -# Copyright (c) 2002 Akinori MUSHA <knu@iDaemons.org> -# -# All rights reserved. -# -# You can redistribute and/or modify it under the same terms as Ruby. -# - -=begin -= set.rb - -This library provides the Set class that deals with a collection of -unordered values with no duplicates. It is a hybrid of Array's -intuitive inter-operation facilities and Hash's fast lookup. - -== Example - - require 'set' - - set1 = Set.new ["foo", "bar", "baz"] - - p set1 #=> #<Set: {"baz", "foo", "bar"}> - - p set1.include?("bar") #=> true - - set1.add("heh") - set1.delete("foo") - - p set1 #=> #<Set: {"heh", "baz", "bar"}> - -== Set class -Set implements a collection of unordered values with no duplicates. -This is a hybrid of Array's intuitive inter-operation facilities and -Hash's fast lookup. - -The equality of each couple of elements is determined according to -Object#eql? and Object#hash, since Set uses Hash as storage. - -=== Included Modules - Enumerable - -=== Class Methods ---- Set::new(enum = nil) - Creates a new set containing the elements of the given enumerable - object. - ---- Set[*ary] - Creates a new set containing the given objects. - -=== Instance Methods ---- dup - Duplicates the set. - ---- size ---- length - Returns the number of elements. - ---- empty? - Returns true if the set contains no elements. - ---- clear - Removes all elements and returns self. - ---- replace(enum) - Replaces the contents of the set with the contents of the given - enumerable object and returns self. - ---- flatten - Returns a new set that is a copy of the set, flattening each - containing set recursively. - ---- flatten! - Equivalent to Set#flatten, but replaces the receiver with the - result in place. Returns nil if no modifications were made. - ---- to_a - Converts the set to an array. (the order is uncertain) - ---- include?(o) ---- member?(o) - Returns true if the set contains the given object. - ---- contain?(enum) - Returns true if the set contains every element of the given - enumerable object. - ---- each { |o| ... } - Calls the given block once for each element in the set, passing - the element as parameter. - ---- add(o) ---- << o - Adds the given object to the set and returns self. - ---- delete(o) - Deletes the given object from the set and returns the object. If - the object is not found, returns nil. - ---- delete_if { |o| ... } - Deletes every element of the set for which block evaluates to - true, and returns self. - ---- reject! { |o| ... } - Equivalent to Set#delete_if, but returns nil if no changes were - made. - ---- merge(enum) - Merges the elements of the given enumerable object to the set and - returns self. - ---- subtract(enum) - Deletes every element that appears in the given enumerable object - and returns self. - ---- + enum ---- | enum - Returns a new set built by merging the set and the elements of the - given enumerable object. - ---- - enum - Returns a new set built by duplicating the set, removing every - element that appear in the given enumerable object. - ---- & enum - Returns a new array containing elements common to the set and the - given enumerable object. - ---- ^ enum - Returns a new array containing elements exclusive between the set - and the given enumerable object. (set ^ enum) is equivalent to - ((set | enum) - (set & enum)). - ---- == set - Returns true if two sets are equal. The equality of each couple - of elements is defined according to Object#eql?. - ---- classify { |o| ... } - Classifies the set by the return value of the given block and - returns a hash of {value => set of elements} pairs. The block is - called once for each element of the set, passing the element as - parameter. - - e.g.: - - require 'set' - files = Set.new(Dir.glob("*.rb")) - hash = files.classify { |f| File.mtime(f).year } - p hash #=> {2000=>#<Set: {"a.rb", "b.rb"}>, - # 2001=>#<Set: {"c.rb", "d.rb", "e.rb"}>, - # 2002=>#<Set: {"f.rb"}>} - ---- divide { |o| ... } ---- divide { |o1, o2| ... } - - Divides the set into a set of subsets according to the commonality - defined by the given block. - - If the arity of the block is 2, elements o1 and o2 are in common - if block.call(o1, o2) is true. Otherwise, elements o1 and o2 are - in common if block.call(o1) == block.call(o2). - - e.g.: - - require 'set' - numbers = Set[1, 3, 4, 6, 9, 10, 11] - set = numbers.divide { |i,j| (i - j).abs == 1 } - p set #=> #<Set: {#<Set: {1}>, - # #<Set: {11, 9, 10}>, - # #<Set: {3, 4}>, - # #<Set: {6}>}> - ---- inspect - Returns a string containing a human-readable representation of the - set. ("#<Set: {element1, element2, ...}>") - -=end - -class Set - include Enumerable - - def self.[](*ary) - new(ary) - end - - def initialize(enum = nil) - @hash = {} - - if enum - enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" - enum.each { |o| @hash[o] = true } - end - end - - def dup - n = type.new - @hash.each_key { |o| n.add(o) } - n - end - - def size - @hash.size - end - alias length size - - def empty? - @hash.empty? - end - - def clear - @hash.clear - self - end - - def replace(enum) - enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" - clear - enum.each { |o| add(o) } - self - end - - def to_a - @hash.keys - end - - def _flatten(set, ids = type.new, result = type.new) - setid = set.id - - ids.include?(setid) and raise ArgumentError, "tried to flatten recursive #{type.name}" - - ids.add(setid) - - set.each { |o| - if o.is_a?(type) - _flatten(o, ids, result) - else - result.add(o) - end - } - - result - end - private :_flatten - - def flatten - _flatten(self) - end - - def flatten! - ids = type.new - replace(_flatten(self, ids)) - - ids.size == 1 ? nil : self - end - - def include?(o) - @hash.include?(o) - end - alias member? include? - - def contain?(enum) - enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" - enum.each { |o| include?(o) or return false } - true - end - - def each - @hash.each_key { |o| yield o } - end - - def add(o) - @hash[o] = true - self - end - alias << add - - def delete(o) - @hash.delete(o) ? o : nil - end - - def delete_if - @hash.delete_if { |key, value| yield(key) } - self - end - - def reject! - n = @hash.size - @hash.delete_if { |key, value| yield(key) } - @hash.size == n ? nil : self - end - - def merge(enum) - enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" - enum.each { |o| add(o) } - self - end - - def subtract(enum) - enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" - enum.each { |o| delete(o) } - self - end - - def +(enum) - enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" - n = dup - enum.each { |o| n.add(o) } - n - end - alias | + ## - - def -(enum) - enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" - n = dup - enum.each { |o| n.delete(o) } - n - end - - def &(enum) - enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" - n = type.new - enum.each { |o| include?(o) and n.add(o) } - n - end - - def ^(enum) - enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" - n = dup - enum.each { |o| if n.include?(o) then n.delete(o) else n.add(o) end } - n - end - - def ==(set) - equal?(set) and return true - - set.is_a?(Set) && size == set.size or return false - - set.each { |o| include?(o) or return false } - - true - end - - def hash - @hash.hash - end - - def eql?(o) - @hash.hash == o.hash - end - - def classify - h = {} - - each { |i| - x = yield(i) - (h[x] ||= type.new).add(i) - } - - h - end - - def divide(&func) - if func.arity == 2 - require 'tsort' - - class << dig = {} - 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 = type.new() - dig.each_strongly_connected_component { |css| - set.add(Set.new(css)) - } - set - else - type.new(classify(&func).values) - end - end - - InspectKey = :__inspect_key__ - - def inspect - ids = (Thread.current[InspectKey] ||= []) - - if ids.include?(id) - return sprintf('#<%s: {...}>', type.name) - end - - begin - ids << id - return sprintf('#<%s: {%s}>', type, to_a.inspect[1..-2]) - ensure - ids.pop - end - end - - def pretty_print(pp) - pp.text sprintf('#<%s: {', type.name) - pp.nest(1) { - first = true - each { |o| - if first - first = false - else - pp.text "," - pp.breakable - end - pp.pp o - } - } - pp.text "}>" - end - - def pretty_print_cycled(pp) - pp.text sprintf('#<%s: {%s}>', type.name, empty? ? '' : '...') - end -end - -=begin -if $0 == __FILE__ - require 'test/unit' - require 'test/unit/ui/console/testrunner' - - class TC_Set < Test::Unit::TestCase - def test_aref - assert_nothing_raised { - Set[] - Set[nil] - Set[1,2,3] - } - - assert_equal(0, Set[].size) - assert_equal(1, Set[nil].size) - assert_equal(1, Set[[]].size) - assert_equal(1, Set[[nil]].size) - - set = Set[2,4,6,4] - assert_equal(Set.new([2,4,6]), set) - end - - def test_s_new - assert_nothing_raised { - Set.new() - Set.new(nil) - Set.new([]) - Set.new([1,2]) - Set.new('a'..'c') - Set.new('XYZ') - } - assert_raises(ArgumentError) { - Set.new(1) - } - assert_raises(ArgumentError) { - Set.new(1,2) - } - - assert_equal(0, Set.new().size) - assert_equal(0, Set.new(nil).size) - assert_equal(0, Set.new([]).size) - assert_equal(1, Set.new([nil]).size) - - ary = [2,4,6,4] - set = Set.new(ary) - ary.clear - assert_equal(false, set.empty?) - assert_equal(3, set.size) - end - - def test_dup - set1 = Set[1,2] - set2 = set1.dup - - assert_not_same(set1, set2) - - assert_equal(set1, set2) - - set1.add(3) - - assert_not_equal(set1, set2) - end - - def test_size - assert_equal(0, Set[].size) - assert_equal(2, Set[1,2].size) - assert_equal(2, Set[1,2,1].size) - end - - def test_empty? - assert_equal(true, Set[].empty?) - assert_equal(false, Set[1, 2].empty?) - end - - def test_clear - set = Set[1,2] - ret = set.clear - - assert_same(set, ret) - assert_equal(true, set.empty?) - end - - def test_replace - set = Set[1,2] - ret = set.replace('a'..'c') - - assert_same(set, ret) - assert_equal(Set['a','b','c'], set) - end - - def test_to_a - set = Set[1,2,3,2] - ary = set.to_a - - assert_equal([1,2,3], ary.sort) - end - - def test_flatten - set1 = Set[ - 1, - Set[ - 5, - Set[7, - Set[0] - ], - Set[6,2], - 1 - ], - 3, - Set[3,4] - ] - - set2 = set1.flatten - set3 = Set.new(0..7) - - assert_not_same(set2, set1) - assert_equal(set3, set2) - - # destructive - orig_set1 = set1 - set1.flatten! - - assert_same(orig_set1, set1) - assert_equal(set3, set1) - end - - def test_include? - set = Set[1,2,3] - - assert_equal(true, set.include?(1)) - assert_equal(true, set.include?(2)) - assert_equal(true, set.include?(3)) - assert_equal(false, set.include?(0)) - assert_equal(false, set.include?(nil)) - - set = Set["1",nil,"2",nil,"0","1",false] - assert_equal(true, set.include?(nil)) - assert_equal(true, set.include?(false)) - assert_equal(true, set.include?("1")) - assert_equal(false, set.include?(0)) - assert_equal(false, set.include?(true)) - end - - def test_contain? - set = Set[1,2,3] - - assert_raises(ArgumentError) { - set.contain?() - } - - assert_raises(ArgumentError) { - set.contain?(2) - } - - assert_equal(true, set.contain?([])) - assert_equal(true, set.contain?([3,1])) - assert_equal(false, set.contain?([1,2,0])) - - assert_equal(true, Set[].contain?([])) - end - - def test_each - ary = [1,3,5,7,10,20] - set = Set.new(ary) - - assert_raises(LocalJumpError) { - set.each - } - - assert_nothing_raised { - set.each { |o| - ary.delete(o) or raise "unexpected element: #{o}" - } - - ary.empty? or raise "forgotten elements: #{ary.join(', ')}" - } - end - - def test_add - set = Set[1,2,3] - - ret = set.add(2) - assert_same(set, ret) - assert_equal(Set[1,2,3], set) - - ret = set.add(4) - assert_same(set, ret) - assert_equal(Set[1,2,3,4], set) - end - - def test_delete - set = Set[1,2,3] - - ret = set.delete(4) - assert_same(nil, ret) - assert_equal(Set[1,2,3], set) - - ret = set.delete(2) - assert_equal(2, ret) - assert_equal(Set[1,3], set) - end - - def test_delete_if - set = Set.new(1..10) - ret = set.delete_if { |i| i > 10 } - assert_same(set, ret) - assert_equal(Set.new(1..10), set) - - set = Set.new(1..10) - ret = set.delete_if { |i| i % 3 == 0 } - assert_same(set, ret) - assert_equal(Set[1,2,4,5,7,8,10], set) - end - - def test_reject! - set = Set.new(1..10) - ret = set.reject! { |i| i > 10 } - assert_same(nil, ret) - assert_equal(Set.new(1..10), set) - - set = Set.new(1..10) - ret = set.delete_if { |i| i % 3 == 0 } - assert_same(set, ret) - assert_equal(Set[1,2,4,5,7,8,10], set) - end - - def test_merge - set = Set[1,2,3] - - ret = set.merge([2,4,6]) - assert_same(set, ret) - assert_equal(Set[1,2,3,4,6], set) - end - - def test_subtract - set = Set[1,2,3] - - ret = set.subtract([2,4,6]) - assert_same(set, ret) - assert_equal(Set[1,3], set) - end - - def test_plus - set = Set[1,2,3] - - ret = set + [2,4,6] - assert_not_same(set, ret) - assert_equal(Set[1,2,3,4,6], ret) - end - - def test_minus - set = Set[1,2,3] - - ret = set - [2,4,6] - assert_not_same(set, ret) - assert_equal(Set[1,3], ret) - end - - def test_and - set = Set[1,2,3,4] - - ret = set & [2,4,6] - assert_not_same(set, ret) - assert_equal(Set[2,4], ret) - end - - def test_eq - set1 = Set[2,3,1] - set2 = Set[1,2,3] - - assert_equal(set1, set1) - assert_equal(set1, set2) - assert_not_equal(Set[1], [1]) - end - - # def test_hash - # end - - # def test_eql? - # end - - def test_classify - set = Set.new(1..10) - ret = set.classify { |i| i % 3 } - - assert_equal(3, ret.size) - assert_instance_of(Hash, ret) - ret.each_value { |value| assert_instance_of(Set, value) } - assert_equal(Set[3,6,9], ret[0]) - assert_equal(Set[1,4,7,10], ret[1]) - assert_equal(Set[2,5,8], ret[2]) - end - - def test_divide - set = Set.new(1..10) - ret = set.divide { |i| i % 3 } - - assert_equal(3, ret.size) - n = 0 - ret.each { |s| n += s.size } - assert_equal(set.size, n) - assert_equal(set, ret.flatten) - - set = Set[7,10,5,11,1,3,4,9,0] - ret = set.divide { |a,b| (a - b).abs == 1 } - - assert_equal(4, ret.size) - n = 0 - ret.each { |s| n += s.size } - assert_equal(set.size, n) - assert_equal(set, ret.flatten) - ret.each { |s| - if s.include?(0) - assert_equal(Set[0,1], s) - elsif s.include?(3) - assert_equal(Set[3,4,5], s) - elsif s.include?(7) - assert_equal(Set[7], s) - elsif s.include?(9) - assert_equal(Set[9,10,11], s) - else - raise "unexpected group: #{s.inspect}" - end - } - end - - def test_inspect - set1 = Set[1] - - assert_equal('#<Set: {1}>', set1.inspect) - - set2 = Set[Set[0], 1, 2, set1] - assert_equal(false, set2.inspect.include?('#<Set: {...}>')) - - set1.add(set2) - assert_equal(true, set1.inspect.include?('#<Set: {...}>')) - end - - # def test_pretty_print - # end - - # def test_pretty_print_cycled - # end - end - - Test::Unit::UI::Console::TestRunner.run(TC_Set) -end -=end |
