multiset 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|