multiset 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.autotest +23 -0
- data/.gemtest +0 -0
- data/History.txt +206 -0
- data/README.txt +84 -0
- data/Rakefile +17 -44
- data/lib/multimap.rb +480 -0
- data/lib/multiset.rb +1135 -121
- data/spec/multiset_spec.rb +619 -2
- data/spec/spec_helper.rb +0 -8
- metadata +68 -118
- data/.document +0 -5
- data/.rspec +0 -1
- data/Gemfile +0 -13
- data/LICENSE.txt +0 -20
- data/README.rdoc +0 -19
- data/VERSION +0 -1
- data/lib/multiset/libmultimap.rb +0 -475
- data/lib/multiset/libmultiset.rb +0 -757
- data/multiset.gemspec +0 -66
- data/spec/multiset_spec_ported.rb +0 -528
data/.autotest
ADDED
@@ -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
|
data/.gemtest
ADDED
File without changes
|
data/History.txt
ADDED
@@ -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
|
data/README.txt
ADDED
@@ -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
|
-
|
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 '
|
30
|
-
require '
|
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
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/multimap.rb
ADDED
@@ -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
|