multiset 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ # Autotest.add_hook :initialize do |at|
6
+ # at.extra_files << "../some/external/dependency.rb"
7
+ #
8
+ # at.libs << ":../some/external"
9
+ #
10
+ # at.add_exception 'vendor'
11
+ #
12
+ # at.add_mapping(/dependency.rb/) do |f, _|
13
+ # at.files_matching(/test_.*rb$/)
14
+ # end
15
+ #
16
+ # %w(TestA TestB).each do |klass|
17
+ # at.extra_class_map[klass] = "test/test_misc.rb"
18
+ # end
19
+ # end
20
+
21
+ # Autotest.add_hook :run_command do |at|
22
+ # system "rake build"
23
+ # end
File without changes
@@ -0,0 +1,206 @@
1
+ === 0.1.0 / 2008-02-09
2
+
3
+ (ja)
4
+ * 公開開始。
5
+
6
+ (en)
7
+ * First distribution.
8
+
9
+ === 0.1.1 / 2008-02-12
10
+
11
+ (ja)
12
+ * Multiset#&の実装が誤っていたのを修正。
13
+ * ドキュメントの間違いを修正。
14
+
15
+ (en)
16
+ * Fixed: Wrong implementation of Multiset#&
17
+ * Fixed: Wrong documentation
18
+
19
+ === 0.1.2 / 2008-02-16
20
+
21
+ (ja)
22
+ * Hash#to_multisetに冗長な処理があったので修正。
23
+ * Multisetにメソッドmap, map!, collect, collect!, map_with, map_with!を追加。
24
+ * これに伴い、従来のMultiset#mapなどとは挙動が変更されました。
25
+ (従来のMultiset#mapなどはEnumerable#mapを呼んでいたので、
26
+ 返り値は配列でした。)
27
+
28
+ (en)
29
+ * Fixed: Removing redundant process in Hash#to_multiset
30
+ * Added: Methods: map, map!, collect, collect!, map_with, map_with! on Multiset
31
+ * As a result, what Multiset#map and other methods do has changed.
32
+ (As of version 0.11, Multiset#map returns an array, because
33
+ Multiset#map means Enumerable#map.)
34
+
35
+ === 0.1.3 / 2008-03-01
36
+
37
+ (ja)
38
+ * setup.rb(http://i.loveruby.net/ja/projects/setup/)を用いたインストールに対応した。
39
+
40
+ (en)
41
+ * Made setup.rb(http://i.loveruby.net/en/projects/setup/) be avaliable.
42
+
43
+ === 0.1.3.1 / 2008-03-02
44
+
45
+ (ja)
46
+ * ドキュメントの間違いを修正。
47
+
48
+ (en)
49
+ * Fixed: Wrong documentation
50
+
51
+ === 0.2.0 / 2008-03-23
52
+
53
+ (ja)
54
+ * Multimapクラスを追加。またこれに伴い、Hash#to_multimap・Hash#multimap
55
+ メソッドを追加。
56
+ * Multiset.parse、Multiset.parse_force、Multiset.parse_string、
57
+ Multiset.parse_string?メソッドを追加。
58
+ * Multiset#==において、引数がMultisetのインスタンスでない場合、
59
+ 強制的にfalseを返すようにした。
60
+ * Multiset#subset?、Multiset#superset?、Multiset#proper_subset?、
61
+ Multiset#proper_superset?において、引数がMultisetのインスタンスで
62
+ ない場合、強制的にArgumentErrorを発生するようにした。
63
+
64
+ (en)
65
+ * Added: Multimap class, Hash#to_multimap, Hash#multimap
66
+ * Added: Multiset.parse, Multiset.parse_force, Multiset.parse_string, Multiset.parse_string?
67
+ * Changed: In Multiset#==, if the argument is not an instance of Multiset,
68
+ Multiset#== always returns false.
69
+ * Changed: In Multiset#subset?, Multiset#superset?, Multiset#proper_subset?
70
+ and Multiset#proper_superset?, if the argument is not an instance of Multiset,
71
+ those methods always raise ArgumentError.
72
+
73
+ === 0.2.0.1 / 2008-03-25
74
+
75
+ (ja)
76
+ * Multiset#classify、Multiset#classify_withの返り値をMultimapにした。
77
+ * Multimap#to_s、Multimap#inspectを追加。(ドキュメントは省略させていただきます)
78
+ * Multiset#to_sの実装が誤っていたのを修正。
79
+
80
+ (en)
81
+ * Changed: Multiset#classify, Multiset#classify_with returns a Multimap.
82
+ * Added: Multimap#to_s, Multimap#inspect (No document)
83
+ * Fixed: Wrong implementation of Multiset#to_s
84
+
85
+ === 0.2.0.2 / 2008-04-23
86
+
87
+ (ja)
88
+ * (setup.rbの)GNU LGPLの文書を添付していなかったので追加
89
+
90
+ (en)
91
+ * Added the text of GNU LGPL to the archive (for setup.rb)
92
+
93
+ === 0.3.0 / 2011-3-24
94
+
95
+ (ja)
96
+ * Rubygemsでの公開を開始。
97
+
98
+ (en)
99
+ * Released for Rubygems
100
+
101
+ === 0.4.0 / 2012-08-16
102
+
103
+ (ja)
104
+ * テストケースを追加。
105
+ * Multiset.parse_string、Multiset.parse_string?メソッドを削除。
106
+ * Ruby1.9でString#eachが削除されたため。
107
+ 文字列を行単位で区切ってMultisetにしたい場合は、Multiset.parse_forceを
108
+ ご利用下さい。
109
+ * Multiset.from_linesメソッドを新設。(文字列のみ渡せます。挙動はMultiset.parse_forceと同じです)
110
+ * Multiset#countはEnumerable#countと同様、ブロックを与えることが可能になりました。
111
+ * Multiset#each, Multiset#each_item, Multiset#each_pairは、ブロックを与えなかった場合にEnumeratorを返すようになりました。
112
+ * 以下のエイリアスを追加。(主に、Enumerableのメソッド名に合わせるため)
113
+ * Multiset#sample (Multiset#randに同じ)
114
+ * Multiset#group_by (Multiset#classifyに同じ)
115
+ * Multiset#group_by_with (Multiset#classify_withに同じ)
116
+ * Multiset#each_with_count (Multiset#each_pairに同じ)
117
+ * 以下の「含まれている要素とその個数について繰り返す」メソッドを追加。
118
+ * Multiset#find_with, Multiset#detect_with
119
+ * Multiset#find_all_with, Multiset#select_with
120
+ * Multiset#reject_with
121
+ * Multiset#inject_with, Multiset#reduce_with
122
+ * Multiset#max_with
123
+ * Multiset#min_with
124
+ * Multiset#minmax_with
125
+ * Multiset#max_by_with
126
+ * Multiset#min_by_with
127
+ * Multiset#minmax_by_with
128
+ * Multiset#sort_with
129
+ * Multiset#sort_by_with
130
+ * バージョン0.4.0より、以下のメソッドはArrayではなくMultisetを返します。
131
+ * Multiset#map, Multiset#collect
132
+ * Multiset#map!, Multiset#collect!
133
+ * Multiset#find_all, Multiset#select
134
+ * Multiset#grep
135
+ * Multiset#reject
136
+ * バージョン0.4.0より、以下のメソッドはHashではなくMultimapを返します。
137
+ * Multiset#group_by (returned as a result of becoming an alias of Multiset#classify)
138
+ * バージョン0.4.0より、以下のメソッドは冗長な処理を回避する仕様となっています。具体的には、これまではMultiset#eachに従って同じ要素を何度もブロックに渡していたものを、Multiset#each_itemに従って同じ要素は1度しかブロックに渡さなくなりました。例えば、Multiset[:a, :a, :a, :b].map{ ... }は新しい挙動ではブロックを2回しか呼びません(これまでの挙動では4回呼んでいた)。
139
+ * Multiset#map, Multiset#collect
140
+ * Multiset#map!, Multiset#collect!
141
+ * Multiset#find_all, Multiset#select
142
+ * Multiset#grep
143
+ * Multiset#reject
144
+ * Multiset#reject!
145
+ * Multiset#delete_if
146
+ * Multiset#classify
147
+ * Multiset#max
148
+ * Multiset#min
149
+ * Multiset#minmax
150
+ * Multiset#max_by
151
+ * Multiset#min_by
152
+ * Multiset#minmax_by
153
+ * Multiset#sort
154
+ * Multiset#sort_by
155
+
156
+ (en)
157
+ * Added: Test codes
158
+ * Removed: Multiset.parse_string, Multiset.parse_string?
159
+ * Because Ruby 1.9 does not support String#each
160
+ * Multiset.parse_force is still available.
161
+ * Added: Multiset.from_lines (equivalent to Multiset.parse_force, but only a string is accepted)
162
+ * Fixed: Multiset#count behaves like Enumerable#count: you can give it a block.
163
+ * Fixed: Multiset#each, Multiset#each_item, Multiset#each_pair: they return an Enumerator if no block is given.
164
+ * Added: Some aliases (mainly to fit with the methods in Enumerable)
165
+ * Multiset#sample (alias of Multiset#rand)
166
+ * Multiset#group_by (alias of Multiset#classify)
167
+ * Multiset#group_by_with (alias of Multiset#classify_with)
168
+ * Multiset#each_with_count (alias of Multiset#each_pair)
169
+ * Added: Iteration methods which gives pairs of items/counts
170
+ * Multiset#find_with, Multiset#detect_with
171
+ * Multiset#find_all_with, Multiset#select_with
172
+ * Multiset#reject_with
173
+ * Multiset#inject_with, Multiset#reduce_with
174
+ * Multiset#max_with
175
+ * Multiset#min_with
176
+ * Multiset#minmax_with
177
+ * Multiset#max_by_with
178
+ * Multiset#min_by_with
179
+ * Multiset#minmax_by_with
180
+ * Multiset#sort_with
181
+ * Multiset#sort_by_with
182
+ * Modified: The following methods are to return a Multiset rather than an Array since version 0.4.0.
183
+ * Multiset#map, Multiset#collect
184
+ * Multiset#map!, Multiset#collect!
185
+ * Multiset#find_all, Multiset#select
186
+ * Multiset#grep
187
+ * Multiset#reject
188
+ * Modified: The following methods are to return a Multimap rather than a Hash of Arrays since version 0.4.0.
189
+ * Multiset#group_by (returned as a result of becoming an alias of Multiset#classify)
190
+ * Modified: To avoid redundancy, following methods are to scan the Multiset for each (non-duplicated) elements since 0.4.0, that is, the same behavior as Multiset#each_item. For example, Multiset[:a, :a, :a, :b].map{ ... } calls the block for only twice, which is 4 times in the old behavior.
191
+ * Multiset#map, Multiset#collect
192
+ * Multiset#map!, Multiset#collect!
193
+ * Multiset#find_all, Multiset#select
194
+ * Multiset#grep
195
+ * Multiset#reject
196
+ * Multiset#reject!
197
+ * Multiset#delete_if
198
+ * Multiset#classify
199
+ * Multiset#max
200
+ * Multiset#min
201
+ * Multiset#minmax
202
+ * Multiset#max_by
203
+ * Multiset#min_by
204
+ * Multiset#minmax_by
205
+ * Multiset#sort
206
+ * Multiset#sort_by
@@ -0,0 +1,84 @@
1
+ = multiset
2
+
3
+ * http://maraigue.hhiro.net/multiset/
4
+
5
+ Ruby implementation of the multiset
6
+
7
+ == DESCRIPTION:
8
+
9
+ Unlike ordinary set(see Ruby documentation for "set" library), multiset can contain two or more same items.
10
+
11
+ Set[:a,:b,:c,:b,:b,:c] # => #<Set: {:b, :c, :a}>
12
+ Multiset[:a,:b,:c,:b,:b,:c] # => #<Multiset:#3 :b, #2 :c, #1 :a>
13
+
14
+ Multisets are typically used for counting elements and their appearances in collections.
15
+
16
+ == FEATURES/PROBLEMS:
17
+
18
+ * Nothing for now
19
+
20
+ == SYNOPSIS:
21
+
22
+ # Creating a multiset
23
+ Set[:a,:b,:c,:b,:b,:c] # => #<Set: {:b, :c, :a}>
24
+ Multiset[:a,:b,:c,:b,:b,:c] # => #<Multiset:#3 :b, #2 :c, #1 :a>
25
+
26
+ # Counting the appearances of characters in a string
27
+ m = Multiset.new
28
+ "abracadabra".each_char do |c| # replace with 'each_byte' in Ruby 1.8.6 or before
29
+ m << c
30
+ end
31
+ p m
32
+ # => #<Multiset:#5 "a", #2 "b", #2 "r", #1 "c", #1 "d">
33
+
34
+ # The same
35
+ Multiset.new("abracadabra".split(//))
36
+ # => #<Multiset:#5 "a", #2 "b", #2 "r", #1 "c", #1 "d">
37
+
38
+ # The same, but available with Ruby 1.8.7 or after
39
+ Multiset.new("abracadabra".each_char)
40
+ # => #<Multiset:#5 "a", #2 "b", #2 "r", #1 "c", #1 "d">
41
+
42
+ See also: http://maraigue.hhiro.net/multiset/reverseref.en.html
43
+
44
+ == REQUIREMENTS:
45
+
46
+ No specific external libraries/tools are required.
47
+
48
+ == INSTALL:
49
+
50
+ gem install multiset
51
+
52
+ == DEVELOPERS:
53
+
54
+ After checking out the source, run:
55
+
56
+ $ rake newb
57
+
58
+ This task will install any missing dependencies, run the tests/specs,
59
+ and generate the RDoc.
60
+
61
+ == LICENSE:
62
+
63
+ (The MIT License)
64
+
65
+ Copyright (c) 2008-2012 H.Hiro (Maraigue)
66
+
67
+ Permission is hereby granted, free of charge, to any person obtaining
68
+ a copy of this software and associated documentation files (the
69
+ 'Software'), to deal in the Software without restriction, including
70
+ without limitation the rights to use, copy, modify, merge, publish,
71
+ distribute, sublicense, and/or sell copies of the Software, and to
72
+ permit persons to whom the Software is furnished to do so, subject to
73
+ the following conditions:
74
+
75
+ The above copyright notice and this permission notice shall be
76
+ included in all copies or substantial portions of the Software.
77
+
78
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
79
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
80
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
81
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
82
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
83
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
84
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,50 +1,23 @@
1
- require 'rubygems'
2
- require 'bundler'
3
- begin
4
- Bundler.setup(:default, :development)
5
- rescue Bundler::BundlerError => e
6
- $stderr.puts e.message
7
- $stderr.puts "Run `bundle install` to install missing gems"
8
- exit e.status_code
9
- end
10
- require 'rake'
11
-
12
- require 'jeweler'
13
- Jeweler::Tasks.new do |gem|
14
- # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
- gem.name = "multiset"
16
- gem.homepage = "http://github.com/maraigue/multiset"
17
- gem.license = "MIT"
18
- gem.summary = %Q{Multiset library for Ruby}
19
- gem.description = %Q{Ruby implementation of multiset. Unlike ordinary set(see Ruby documentation for "set" library), multiset can contain two or more same items.}
20
- gem.email = "main@hhiro.net"
21
- gem.authors = ["H.Hiro(Maraigue)"]
22
- # Include your dependencies below. Runtime dependencies are required when using your gem,
23
- # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
- # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
- # gem.add_development_dependency 'rspec', '> 1.2.3'
26
- end
27
- Jeweler::RubygemsDotOrgTasks.new
1
+ # -*- ruby -*-
28
2
 
29
- require 'rspec/core'
30
- require 'rspec/core/rake_task'
31
- RSpec::Core::RakeTask.new(:spec) do |spec|
32
- spec.pattern = FileList['spec/**/*_spec.rb']
33
- end
3
+ require 'rubygems'
4
+ require 'hoe'
34
5
 
35
- RSpec::Core::RakeTask.new(:rcov) do |spec|
36
- spec.pattern = 'spec/**/*_spec.rb'
37
- spec.rcov = true
38
- end
6
+ # Hoe.plugin :compiler
7
+ # Hoe.plugin :gem_prelude_sucks
8
+ # Hoe.plugin :inline
9
+ # Hoe.plugin :racc
10
+ # Hoe.plugin :rcov
11
+ # Hoe.plugin :rubyforge
39
12
 
40
- task :default => :spec
13
+ Hoe.spec 'multiset' do
14
+ # HEY! If you fill these out in ~/.hoe_template/Rakefile.erb then
15
+ # you'll never have to touch them again!
16
+ # (delete this comment too, of course)
41
17
 
42
- require 'rake/rdoctask'
43
- Rake::RDocTask.new do |rdoc|
44
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
18
+ developer('H.Hiro(Maraigue)', 'main@hhiro.net')
45
19
 
46
- rdoc.rdoc_dir = 'rdoc'
47
- rdoc.title = "multiset #{version}"
48
- rdoc.rdoc_files.include('README*')
49
- rdoc.rdoc_files.include('lib/**/*.rb')
20
+ # self.rubyforge_name = 'multisetx' # if different than 'multiset'
50
21
  end
22
+
23
+ # vim: syntax=ruby
@@ -0,0 +1,480 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ require "multiset"
5
+
6
+ #==概要(Basic information)
7
+ #
8
+ #Rubyによる多重連想配列(マルチマップ)の実装です。
9
+ #通常の連想配列(Rubyでは"Hash"クラス)と異なり、多重連想配列は
10
+ #1つのキーに対して複数の要素が存在し得ます。
11
+ #
12
+ #メソッド名は基本的にHashクラスに合わせてあります。またHashクラスが持つ
13
+ #メソッドの大部分を実装していますが、いくつか未実装なものもあります。
14
+ #
15
+ #Ruby implementation of multimap.
16
+ #Unlike ordinary map, also known as associative array
17
+ #(see Ruby documentation for "Hash" class),
18
+ #multimap can contain two or more items for a key.
19
+ #
20
+ #Most methods' names are same as those of Hash class, and all other than
21
+ #a few methods in Hash class is implemented on Multimap class.
22
+
23
+ class Multimap
24
+ include Enumerable
25
+
26
+ #--
27
+ # Constructors
28
+ #++
29
+
30
+ # 新しい多重連想配列を生成します。Hash#newと異なり、デフォルト値は
31
+ # 設定できません。
32
+ #
33
+ # Generates a new multimap. Different from Hash#new , you can not
34
+ # specify default value.
35
+ def initialize
36
+ @assoc = Hash.new{ |hash, key| hash[key] = Multiset.new }
37
+ end
38
+
39
+ # Removes all keys in @assoc if the value associated with key is
40
+ # empty multiset.
41
+ def cleanup # :nodoc:
42
+ @assoc.reject!{ |key, value_list| value_list.empty? }
43
+ end
44
+ private :cleanup
45
+
46
+ # キー<code>key</code>に対応する値(複数存在しうる)を、
47
+ # Multisetとして返します。Hash#fetchの場合と異なり、キーに対応する
48
+ # 値が存在しない場合の扱いを指定することはできません。
49
+ # (そのような場合、空のMultisetが返ります。)
50
+ #
51
+ # Returns values associated with <code>key</code> with format of
52
+ # Multiset. Different from Hash#fetch, you can not specify
53
+ # a value or a process when <code>key</code> has not associated with
54
+ # any value. If <code>key</code> has not associated with any value,
55
+ # Multimap#fetch returns empty Multiset.
56
+ def fetch(key)
57
+ @assoc[key]
58
+ end
59
+ alias :[] :fetch
60
+
61
+ # キー<code>key</code>に対応する値(複数存在しうる)を
62
+ # <code>value_list</code>で置き換えます。この際、
63
+ # <code>value_list</code>はMultiset.parseを用いてMultisetに変換されます。
64
+ #
65
+ # <code>value_list</code>を返します。
66
+ #
67
+ # Sets values associated with <code>key</code> to <code>value_list</code>.
68
+ # <code>value_list</code> is converted to a Multiset by Multiset.parse .
69
+ #
70
+ # Returns <code>value_list</code>.
71
+ def store(key, value_list)
72
+ if value_list.class == Multiset
73
+ @assoc[key] = value_list.dup
74
+ else
75
+ @assoc[key] = Multiset.parse(value_list)
76
+ end
77
+ value_list
78
+ end
79
+ alias :[]= :store
80
+
81
+ # <code>self</code>が<code>other</code>と等しいかどうかを返します。
82
+ #
83
+ # Returns whether <code>self</code> is equal to <code>other</code>.
84
+ def ==(other)
85
+ return false unless other.instance_of?(Multimap)
86
+ @assoc == other.to_hash
87
+ end
88
+
89
+ # <code>self</code>を<code>Hash</code>に変換して返します。
90
+ # 生成されるハッシュの構造については、Hash#to_multimapをご覧下さい。
91
+ # その際、返されるハッシュにおいて値はすべてMultimap型となります。
92
+ #
93
+ # Converts <code>self</code> to a <code>Hash</code>.
94
+ # See Hash#to_multimap about format of generated hash.
95
+ # All values in the returned hash are multimaps.
96
+ def to_hash
97
+ @assoc.dup
98
+ end
99
+
100
+ # <code>self</code>に格納された要素をすべて削除します。
101
+ # <code>self</code>を返します。
102
+ #
103
+ # Removes all elements stored in <code>self</code>.
104
+ # Returns <code>self</code>.
105
+ def clear
106
+ @assoc.clear
107
+ end
108
+
109
+ # <code>self</code>の複製を生成して返します。
110
+ #
111
+ # Returns duplicated <code>self</code>.
112
+ def dup
113
+ @assoc.to_multimap
114
+ end
115
+
116
+ # <code>self</code>の内容を<code>other</code>のものに置き換えます。
117
+ # <code>self</code>を返します。
118
+ #
119
+ # Replaces <code>self</code> by <code>other</code>.
120
+ # Returns <code>self</code>.
121
+ def replace(other)
122
+ @assoc.clear
123
+ other.each_pair_with do |key, a_value, count|
124
+ @assoc[key].add a_value, count
125
+ end
126
+ self
127
+ end
128
+
129
+ # <code>key</code>に割り当てられた全ての値を削除し、その値を
130
+ # Multisetとして返します。
131
+ #
132
+ # Deletes all values associated with <code>key</code>, and returns
133
+ # those values as a Multiset.
134
+ def delete(key)
135
+ ret = @assoc[key]
136
+ @assoc.delete(key)
137
+ ret
138
+ end
139
+
140
+ # delete_ifと同じですが、<code>self</code>自身からはキーと値の組を
141
+ # 削除せず、要素が削除された結果の多重連想配列を新たに生成して
142
+ # 返します。
143
+ #
144
+ # Same as delete_if, but generates a new Multimap whose pairs of
145
+ # key and value are deleted, instead of deleting pairs in
146
+ # <code>self</code>.
147
+ def reject(&block) # :yields: key, single_value
148
+ ret = self.dup
149
+ ret.delete_if &block
150
+ ret
151
+ end
152
+
153
+ # ブロックに<code>self</code>のキーと値の組(値は1つ)を順次与え、
154
+ # 結果が真であった組をすべて削除します。
155
+ # <code>self</code>を返します。
156
+ #
157
+ # Gives all pairs of a key and single value in <code>self</code>
158
+ # to given block, and deletes that element if the block returns true.
159
+ # Returns <code>self</code>.
160
+ def delete_if(&block) # :yields: key, single_value
161
+ cleanup
162
+ @assoc.each_pair do |key, value_list|
163
+ value_list.delete_if{ |single_value|
164
+ block.call(key, single_value)
165
+ }
166
+ end
167
+ self
168
+ end
169
+
170
+ # delete_ifと同じですが、キーと値の組が1つも削除されなければ
171
+ # <code>nil</code>を返します。
172
+ #
173
+ # Same as delete_if, but returns <code>nil</code> if no pair of
174
+ # key and value is deleted.
175
+ def reject!(&block) # :yields: key, single_value
176
+ cleanup
177
+ ret = nil
178
+ @assoc.each_pair do |key, value_list|
179
+ ret = self if value_list.reject!{ |single_value|
180
+ block.call(key, single_value)
181
+ }
182
+ end
183
+ ret
184
+ end
185
+
186
+ # rejectと同じですが、ブロックへの引数が(キー、キーに割り当てられた値、
187
+ # その値がキーに割り当てられている個数)の3つの組で与えられます。
188
+ #
189
+ # Same as reject, but arguments given to block is the tuple of three:
190
+ # (key, one value associated with the key, numbers of that value
191
+ # associated with the key).
192
+ def reject_with(&block) # :yields: key, a_value, count
193
+ ret = self.dup
194
+ ret.delete_with &block
195
+ ret
196
+ end
197
+
198
+ # delete_ifと同じですが、ブロックへの引数が(キー、キーに割り当てられた値、
199
+ # その値がキーに割り当てられている個数)の3つの組で与えられます。
200
+ #
201
+ # Same as delete_if, but arguments given to block is the tuple of three:
202
+ # (key, one value associated with the key, numbers of that value
203
+ # associated with the key).
204
+ def delete_with(&block) # :yields: key, a_value, count
205
+ cleanup
206
+ @assoc.each_pair do |key, value_list|
207
+ value_list.delete_with{ |a_value, count|
208
+ block.call(key, a_value, count)
209
+ }
210
+ end
211
+ self
212
+ end
213
+
214
+ # <code>self</code>のすべてのキーと値の組について繰り返します。
215
+ # <code>self</code>を返します。
216
+ #
217
+ # Iterates for each pair of a key and a value in <code>self</code>.
218
+ # Returns <code>self</code>.
219
+ def each_pair
220
+ cleanup
221
+ @assoc.each_pair do |key, value_list|
222
+ value_list.each do |single_value|
223
+ yield key, single_value
224
+ end
225
+ end
226
+ self
227
+ end
228
+ alias :each :each_pair
229
+
230
+ # <code>self</code>のすべてのキーと値の組について、
231
+ # ブロックに(キー、キーに割り当てられた値、その値が割り当てられた数)
232
+ # の組を与えながら繰り返します。<code>self</code>を返します。
233
+ #
234
+ # Iterates for each pair of a key and a value in <code>self</code>,
235
+ # giving the tuple of three to block:
236
+ # (key, one value associated with the key, numbers of that value
237
+ # associated with the key). Returns <code>self</code>.
238
+ def each_pair_with
239
+ cleanup
240
+ @assoc.each_pair do |key, value_list|
241
+ value_list.each_pair do |a_value, count|
242
+ yield key, a_value, count
243
+ end
244
+ end
245
+ self
246
+ end
247
+
248
+ # <code>self</code>のすべてのキーと、そのキーに割り当てられた
249
+ # すべての値(Multisetで与えられる)の組について繰り返します。
250
+ # <code>self</code>を返します。
251
+ #
252
+ # Iterates for each pair of a key and all values associated with the key
253
+ # (list of values is given as Multiset) in <code>self</code>.
254
+ # Returns <code>self</code>.
255
+ def each_pair_list(&block) # :yields: key, value_list
256
+ cleanup
257
+ @assoc.each_pair &block
258
+ end
259
+
260
+
261
+ # <code>self</code>のすべてのキーについて繰り返します。
262
+ # <code>self</code>を返します。
263
+ #
264
+ # Iterates for each key in <code>self</code>. Returns <code>self</code>.
265
+ def each_key(&block) # :yields: key
266
+ cleanup
267
+ @assoc.each_key &block
268
+ end
269
+
270
+ # <code>self</code>のすべての値について繰り返します。
271
+ # <code>self</code>を返します。
272
+ #
273
+ # Iterates for each value in <code>self</code>. Returns <code>self</code>.
274
+ def each_value(&block) # :yields: single_value
275
+ cleanup
276
+ @assoc.each_value do |value_list|
277
+ value_list.each &block
278
+ end
279
+ end
280
+
281
+ # <code>self</code>のすべてのキーを、配列として返します。
282
+ #
283
+ # Returns an array in which keys in <code>self</code> are stored.
284
+ def keys
285
+ cleanup
286
+ @assoc.keys
287
+ end
288
+
289
+
290
+ # <code>self</code>のすべての値を、Multisetとして返します。
291
+ #
292
+ # Returns a Multiset in which values in <code>self</code> are stored.
293
+ def values
294
+ cleanup
295
+ ret = Multiset.new
296
+ @assoc.each_value do |value_list|
297
+ ret.merge! value_list
298
+ end
299
+ ret
300
+ end
301
+
302
+ # <code>self</code>に要素がないかどうかを返します。
303
+ #
304
+ # Returns whether <code>self</code> has no element.
305
+ def empty?
306
+ cleanup
307
+ @assoc.empty?
308
+ end
309
+
310
+ # <code>self</code>にキー<code>key</code>かあるかどうかを返します。
311
+ #
312
+ # Returns whether <code>self</code> has a key <code>key</code>.
313
+ def has_key?(key)
314
+ cleanup
315
+ @assoc.has_key?(key)
316
+ end
317
+ alias :key? :has_key?
318
+ alias :include? :has_key?
319
+ alias :member? :has_key?
320
+
321
+ # <code>self</code>に値<code>value</code>かあるかどうかを返します。
322
+ #
323
+ # Returns whether <code>self</code> has a value <code>value</code>.
324
+ def has_value?(value)
325
+ self.values.items.include?(value)
326
+ end
327
+ alias :value? :has_value?
328
+
329
+ # <code>self</code>から値が<code>value</code>であるような要素を
330
+ # 検索し、それに対応するキーを返します。該当するキーが複数存在する場合、
331
+ # そのうちの1つを返します。該当するキーが存在しなければ
332
+ # <code>nil</code>を返します。
333
+ #
334
+ # Search a pair of key and value from <code>self</code> such that
335
+ # the value is equal to the argument <code>value</code>.
336
+ # If two or keys are matched, returns one of them.
337
+ # If no key is matched, returns nil.
338
+ def key(value)
339
+ self.each_pair_with do |key, a_value, count|
340
+ return key if value == a_value
341
+ end
342
+ nil
343
+ end
344
+ alias :index :key
345
+
346
+ # <code>self</code>から<code>key_list</code>の各キーに対応する値
347
+ # (Multiset型)を取り出し、それらを配列として返します。
348
+ # すなわち、Multisetを要素とする配列を返します。
349
+ #
350
+ # Gets values (instances of Multiset) of <code>self</code>
351
+ # associated with <code>key_list</code>, and returns those values
352
+ # as an array. i.e. returns an array whose elements are multisets.
353
+ def values_at(*key_list)
354
+ key_list.map{ |key| self[key] }
355
+ end
356
+ alias :indexes :values_at
357
+ alias :indices :values_at
358
+
359
+ # <code>self</code>のキーと値を入れ替えたMultimapを返します。
360
+ # 例えばキー:aに対応する値が2つの:xと1つの:yであれば、変換結果は
361
+ # キー:xに:aが2つ、キー:yに:aが1つ対応するMultimapです。
362
+ #
363
+ # Returns a Multimap whose keys are values in <code>self</code>, and
364
+ # values are keys in <code>self</code>. For example,
365
+ # If <code>self</code> has a key :a associated with two :x and one :y,
366
+ # returned multimap has two keys :x and :y, and their values are
367
+ # two :a and one :a respectively.
368
+ def invert
369
+ ret = Multimap.new
370
+ self.each_pair_with do |key, a_value, count|
371
+ ret[a_value].add key, count
372
+ end
373
+ ret
374
+ end
375
+
376
+ # <code>self</code>に含まれている要素数を返します。
377
+ #
378
+ # Returns number of all elements in <code>self</code>.
379
+ def size
380
+ ret = 0
381
+ self.each_pair_with{ |key, a_value, count| ret += count }
382
+ ret
383
+ end
384
+ alias :length :size
385
+
386
+ # <code>self</code>に<code>other</code>の要素を追加します。
387
+ # <code>self</code>を返します。
388
+ #
389
+ # Add elements in <code>other</code> to <code>self</code>.
390
+ # Returns <code>self</code>.
391
+ def merge!(other)
392
+ other.each_pair_with do |key, a_value, count|
393
+ self[key].add a_value, count
394
+ end
395
+ self
396
+ end
397
+
398
+ # <code>self</code>と<code>other</code>の要素を合わせた多重集合を返します。
399
+ #
400
+ # Returns merged multiset of <code>self</code> and <code>other</code>.
401
+ def merge(other)
402
+ ret = self.dup
403
+ ret.merge! other
404
+ end
405
+ alias :+ :merge
406
+
407
+ def to_s(delim = "\n") # :nodoc:
408
+ cleanup
409
+
410
+ buf = ''
411
+ init = true
412
+ @assoc.each_pair do |key, value_list|
413
+ if init
414
+ init = false
415
+ else
416
+ buf += delim
417
+ end
418
+ buf += "#{key.inspect}=>{"
419
+
420
+ init_val = true
421
+ value_list.each_pair do |a_value, count|
422
+ if init_val
423
+ init_val = false
424
+ else
425
+ buf += ", "
426
+ end
427
+ buf += "\##{count} #{a_value.inspect}"
428
+ end
429
+ buf += "}"
430
+ end
431
+ buf
432
+ end
433
+
434
+ def inspect # :nodoc:
435
+ buf = "#<Multimap:"
436
+ buf += self.to_s(', ')
437
+ buf += '>'
438
+ buf
439
+ end
440
+ end
441
+
442
+ class Hash
443
+ # <code>self</code>を多重連想配列に変換し、その結果を返します。
444
+ # 新しく生成される多重連想配列においてキーに割り当てられる値は、
445
+ # <code>self</code>におけるキーの値をMultiset.parseによって多重集合に
446
+ # 変換したものとなります。
447
+ #
448
+ # (例)キー<code>:a</code>には<code>:x</code>と<code>:y</code>が1個ずつ、
449
+ # キー<code>:b</code>には<code>:x</code>が2個割り当てられた多重連想配列
450
+ #
451
+ # <code>{:a => [:x, :y], :b => [:x, :x]}.to_multimap</code>
452
+ #
453
+ # Generates multiset from <code>self</code>.
454
+ # In generated multiset, values associated with a key are defined by
455
+ # the result of Multiset.parse(values_in_<code>self</code>) .
456
+ #
457
+ # (example)
458
+ # Key <code>:a</code> is associated with values one <code>:x</code> and one <code>:y</code>, and
459
+ # key <code>:b</code> is associated with values two <code>:x</code>
460
+ #
461
+ # <code>{:a => [:x, :y], :b => [:x, :x]}.to_multimap</code>
462
+ def to_multimap
463
+ ret = Multimap.new
464
+ self.each_pair{ |key, val| ret[key] = val }
465
+ ret
466
+ end
467
+
468
+ # <code>self</code>を多重連想配列に変換し、その結果を返します。
469
+ # 新しく生成される多重連想配列においてキーに割り当てられる値は、
470
+ # <code>self</code>に含まれる1要素のみです。
471
+ #
472
+ # Generates multiset from <code>self</code>.
473
+ # In generated multiset, only one value is associated with a key
474
+ # (value in <code>self</code>).
475
+ def multimap
476
+ ret = Multimap.new
477
+ self.each_pair{ |key, val| ret[key] = Multiset[val] }
478
+ ret
479
+ end
480
+ end