multiset 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,133 +1,1147 @@
1
- #Rubyによる多重集合(マルチセット)・多重連想配列(マルチマップ)の実装です。
2
- #
3
- #Ruby implementation of multiset and multimap.
4
- #
5
- #==インストール(Installation)
6
- #
7
- #インストールはsetup.rbによって行われます。詳しくはINSTALL.ja.txtをご覧下さい。
8
- #
9
- #setup.rb performs installation. See INSTALL.en.txt for more information.
10
- #
11
- #==更新履歴(Revision history)
12
- #
13
- #* Version 0.10(2008/2/9)
14
- # * 公開開始。
15
- #* Version 0.11(2008/2/12)
16
- # * Multiset#&の実装が誤っていたのを修正。
17
- # * ドキュメントの間違いを修正。
18
- #* Version 0.12(2008/2/16)
19
- # * Hash#to_multisetに冗長な処理があったので修正。
20
- # * Multisetにメソッドmap, map!, collect, collect!, map_with, map_with!を追加。
21
- # * これに伴い、従来のMultiset#mapなどとは挙動が変更されました。
22
- # (従来のMultiset#mapなどはEnumerable#mapを呼んでいたので、
23
- # 返り値は配列でした。)
24
- #* Version 0.13(2008/3/1)
25
- # * setup.rb(http://i.loveruby.net/ja/projects/setup/)を用いたインストールに対応した。
26
- #* Version 0.131(2008/3/2)
27
- # * ドキュメントの間違いを修正。
28
- #* Version 0.20(beta) (2008/3/23)
29
- # * Multimapクラスを追加。またこれに伴い、Hash#to_multimap・Hash#multimap
30
- # メソッドを追加。
31
- # * Multiset.parse、Multiset.parse_force、Multiset.parse_string、
32
- # Multiset.parse_string?メソッドを追加。
33
- # * Multiset#==において、引数がMultisetのインスタンスでない場合、
34
- # 強制的にfalseを返すようにした。
35
- # * Multiset#subset?、Multiset#superset?、Multiset#proper_subset?、
36
- # Multiset#proper_superset?において、引数がMultisetのインスタンスで
37
- # ない場合、強制的にArgumentErrorを発生するようにした。
38
- #* Version 0.201(beta) (2008/3/25)
39
- # * Multiset#classify、Multiset#classify_withの返り値をMultimapにした。
40
- # * Multimap#to_s、Multimap#inspectを追加。(ドキュメントは省略させていただきます)
41
- # * Multiset#to_sの実装が誤っていたのを修正。
42
- #* Version 0.202(beta) (2008/4/23)
43
- # * GNU LGPLの文書を添付していなかったので追加。申し訳ありません。
44
- #<em></em>
45
- #* Version 0.10(2008/2/9)
46
- # * First distribution.
47
- #* Version 0.11(2008/2/12)
48
- # * [Fixed] Wrong implementation of Multiset#&
49
- # * [Fixed] Wrong documentation
50
- #* Version 0.12(2008/2/16)
51
- # * [Fixed] Removing redundant process in Hash#to_multiset
52
- # * [Added] Methods: map, map!, collect, collect!, map_with, map_with! on Multiset
53
- # * As a result, what Multiset#map and other methods do has changed.
54
- # (As of version 0.11, Multiset#map returns an array, because
55
- # Multiset#map means Enumerable#map.)
56
- #* Version 0.13(2008/3/1)
57
- # * Made setup.rb(http://i.loveruby.net/en/projects/setup/) be avaliable.
58
- #* Version 0.131(2008/3/2)
59
- # * [Fixed] Wrong documentation
60
- #* Version 0.20(beta) (2008/3/23)
61
- # * [Added] Multimap class, Hash#to_multimap, Hash#multimap
62
- # * [Added] Multiset.parse, Multiset.parse_force, Multiset.parse_string, Multiset.parse_string?
63
- # * [Changed] In Multiset#==, if the argument is not an instance of Multiset,
64
- # Multiset#== always returns false.
65
- # * [Changed] In Multiset#subset?, Multiset#superset?, Multiset#proper_subset?
66
- # and Multiset#proper_superset?, if the argument is not an instance of Multiset,
67
- # those methods always raise ArgumentError.
68
- #* Version 0.201(beta) (2008/3/25)
69
- # * [Changed] Multiset#classify, Multiset#classify_with returns a Multimap.
70
- # * [Added] Multimap#to_s, Multimap#inspect (No document)
71
- # * [Fixed] Wrong implementation of Multiset#to_s
72
- #* Version 0.202(beta) (2008/4/23)
73
- # * Added the text of GNU LGPL to the archive. I'm very sorry...
74
- #
75
- #==著作権表示(Copyright)
76
- #
77
- #Author:: Maraigue(http://f52.aaa.livedoor.jp/~maraigue/)
78
- #Version:: 0.202(beta) (2008/4/23)
79
- #Copyright:: (C)2008 Maraigue
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ require "enumerator"
5
+ require "multimap"
6
+ VERSION = "0.4.0"
7
+
8
+ #==概要(Basic information)
80
9
  #
81
- #このプログラムはBSDライセンスにて提供する 無 保 証 のプログラムです。
82
- #詳細はBSDLicense.txtをご覧下さい。
10
+ # Rubyによる多重集合(マルチセット)の実装です。
11
+ # 通常の集合(Rubyでは"set"ライブラリ)と異なり、多重集合は
12
+ # 同一の要素を複数格納することができます。
83
13
  #
84
- #日本語の参考訳は以下のURLにあります。
85
- #http://sourceforge.jp/projects/opensource/wiki/licenses%2Fnew_BSD_license
86
- #ただし、法的にはBSDLicense.txtに書かれた英語の文章のみが有効です。
14
+ # メソッド名は基本的にSetクラスに合わせてあります。またSetクラスが持つ
15
+ # メソッドの大部分を実装していますが、いくつか未実装なものもあります。
87
16
  #
88
- #setup.rbはMinero Aoki氏(http://i.loveruby.net/)の制作です。
89
- #setup.rbのみは、GNU LGPL(version 2.1)のライセンスが適用されます。
90
- #GNU LGPLについてはGNU_LGPL.txtをご覧下さい。
17
+ # Ruby implementation of multiset.
18
+ # Unlike ordinary set(see Ruby documentation for "set" library),
19
+ # multiset can contain two or more same items.
91
20
  #
92
- #This program is distributed with ABSOLUTELY NO WARRANTY, under BSD License.
93
- #See BSDLicense.txt for more detail.
21
+ # Most methods' names are same as those of Set class, and all other than
22
+ # a few methods in Set class is implemented on Multiset class.
94
23
  #
95
- #setup.rb is made by Minero Aoki(http://i.loveruby.net/).
96
- #Only setup.rb is distributed under GNU LGPL(version 2.1).
97
- #See GNU_LGPL.txt for more detail.
24
+ # * <code>Set[:a,:b,:c,:b,:b,:c] => #<Set: {:b, :c, :a}></code>
25
+ # * <code>Multiset[:a,:b,:c,:b,:b,:c] => #<Multiset:<tt>#</tt>3 :b, <tt>#</tt>2 :c, <tt>#</tt>1 :a></code>
26
+
27
+ class Multiset
28
+ include Enumerable
29
+
30
+ #--
31
+ # ============================================================
32
+ # コンストラクタ
33
+ # ============================================================
34
+ #++
35
+
36
+ # <code>list</code>に含まれる要素からなる多重集合を生成します。
37
+ # <code>list</code>を省略した場合、空の多重集合を生成します。
38
+ #
39
+ # <code>list</code>には<code>Enumerable</code>であるオブジェクトのみ
40
+ # 指定できます。そうでない場合、例外<code>ArgumentError</code>が
41
+ # 発生します。
42
+ #
43
+ # Generates a multiset from items in <code>list</code>.
44
+ # If <code>list</code> is omitted, returns empty multiset.
45
+ #
46
+ # <code>list</code> must be <code>Enumerable</code>. If not,
47
+ # <code>ArgumentError</code> is raised.
48
+ def initialize(list = nil)
49
+ @entries = {}
50
+ if list.kind_of?(Enumerable)
51
+ list.each{ |item| add item }
52
+ elsif list != nil
53
+ raise ArgumentError, "Item list must include 'Enumerable' module"
54
+ end
55
+ end
56
+
57
+ # <code>list</code>に含まれる要素からなる多重集合を生成します。
58
+ # <code>new</code>を用いる場合と異なり、引数の1つ1つが多重集合の要素になります。
59
+ #
60
+ # 主に多重集合のリテラルを生成するのに用います。
61
+ #
62
+ # Generates a multiset from items in <code>list</code>.
63
+ # Unlike using <code>new</code>, each argument is one item in generated multiset.
64
+ #
65
+ # This method is mainly used when you generate literal of multiset.
66
+ def Multiset.[](*list)
67
+ Multiset.new(list)
68
+ end
69
+
70
+ # <code>object</code>を多重集合に変換し生成します。
71
+ # * <code>object</code>がMultisetのインスタンスである場合、
72
+ # その複製を返します。
73
+ # * <code>object</code>がMultisetのインスタンスでなく、
74
+ # かつ<code>each_pair</code>メソッドを持っている場合、
75
+ # <code>each_pair</code>から渡される2つの引数について、前者を要素、
76
+ # 後者をその個数とした多重集合を生成します。Hash#to_multisetも
77
+ # ご覧下さい。
78
+ # * <code>object</code>が<code>each_pair</code>メソッドを持っておらず、
79
+ # かつ<code>Enumerable</code>である場合は、Multiset#newと同じ結果です。
80
+ # * それ以外の場合は、例外<code>ArgumentError</code>が発生します。
81
+ #
82
+ # Generates a multiset converting <code>object</code>.
83
+ # * If <code>object</code> is an instance of Multiset, returns
84
+ # duplicated <code>object</code>.
85
+ # * If <code>object</code> is not an instance of Multiset and has
86
+ # the method <code>each_pair</code>,
87
+ # for each pair of two arguments from <code>each_pair</code>,
88
+ # first argument becomes item in multiset and second argument
89
+ # becomes its number. See also Hash#to_multiset .
90
+ # * If <code>object</code> does not have the method <code>each_pair</code>
91
+ # and <code>object</code> includes <code>Enumerable</code>, this method
92
+ # results equal to Multiset#new .
93
+ # * Otherwise, <code>ArgumentError</code> is raised.
94
+ def Multiset.parse(object)
95
+ if object.kind_of?(String)
96
+ raise ArgumentError, "Multiset.parse can not parse strings. If you would like to store string lines to a multiset, use Multiset.from_lines(string)."
97
+ end
98
+
99
+ if object.instance_of?(Multiset)
100
+ ret = object.dup
101
+ else
102
+ ret = Multiset.new
103
+ if defined? object.each_pair
104
+ object.each_pair{ |item, count| ret.add item, count }
105
+ elsif object.kind_of?(Enumerable)
106
+ object.each{ |item| ret.add item }
107
+ else
108
+ raise ArgumentError, "Source of Multiset must have 'each_pair' method or include 'Enumerable' module"
109
+ end
110
+ end
111
+ ret
112
+ end
113
+
114
+ # 文字列を行単位で区切ってMultisetにします。
115
+ #
116
+ # Generates a Multiset from string, separated by lines.
117
+ def Multiset.from_lines(str)
118
+ Multiset.new(str.enum_for(:each_line))
119
+ end
120
+
121
+ # 文字列が渡された場合は、Multiset.from_linesと同じ挙動。
122
+ # それ以外の場合は、Multiset.parseと同じ挙動。
123
+ #
124
+ # If a string is given, it works as Multiset.from_lines,
125
+ # otherwise as Multiset.parse.
126
+ def Multiset.parse_force(object)
127
+ if object.kind_of?(String)
128
+ Multiset.from_lines(object)
129
+ else
130
+ Multiset.parse(object)
131
+ end
132
+ end
133
+
134
+ # <code>self</code>の複製を生成して返します。
135
+ #
136
+ # Returns duplicated <code>self</code>.
137
+ def dup
138
+ @entries.to_multiset
139
+ end
140
+
141
+ # <code>self</code>を<code>Hash</code>に変換して返します。
142
+ # 生成されるハッシュの構造については、Hash#to_multisetをご覧下さい。
143
+ #
144
+ # Converts <code>self</code> to a <code>Hash</code>.
145
+ # See Hash#to_multiset about format of generated hash.
146
+ def to_hash
147
+ @entries.dup
148
+ end
149
+
150
+ #--
151
+ # ============================================================
152
+ # 別の型への変換、基本的な関数など
153
+ # ============================================================
154
+ #++
155
+
156
+ # <code>self</code>を通常の集合(Ruby標準添付の<code>Set</code>)に
157
+ # 変換したものを返します。
158
+ #
159
+ # このメソッドを呼び出すと、<code>require "set"</code>が行われます。
160
+ #
161
+ # なおSetをMultisetに変換するには、<code>Multiset.new(instance_of_set)</code>で
162
+ # 可能です。
163
+ #
164
+ # Converts <code>self</code> to ordinary set
165
+ # (The <code>Set</code> class attached to Ruby by default).
166
+ #
167
+ # <code>require "set"</code> is performed when this method is called.
168
+ #
169
+ # To convert Set to Multiset, use <code>Multiset.new(instance_of_set)</code>.
170
+ def to_set
171
+ require "set"
172
+ Set.new(@entries.keys)
173
+ end
174
+
175
+ # <code>self</code>を配列に変換して返します。
176
+ #
177
+ # Converts <code>self</code> to an array.
178
+ def to_a
179
+ ret = []
180
+ @entries.each_pair do |item, count|
181
+ ret.concat Array.new(count, item)
182
+ end
183
+ ret
184
+ end
185
+
186
+ def hash # :nodoc:
187
+ val = 0
188
+ @entries.each_pair do |item, count|
189
+ val += item.hash * count
190
+ end
191
+ val
192
+ end
193
+
194
+ def eql?(other) # :nodoc:
195
+ if self.hash == other.hash
196
+ self == other
197
+ else
198
+ false
199
+ end
200
+ end
201
+
202
+ #--
203
+ # ============================================================
204
+ # 基本操作(他のメソッドを定義するのに頻出するメソッドなど)
205
+ # ============================================================
206
+ #++
207
+
208
+ # <code>self</code>の内容を<code>other</code>のものに置き換えます。
209
+ # <code>self</code>を返します。
210
+ #
211
+ # Replaces <code>self</code> by <code>other</code>.
212
+ # Returns <code>self</code>.
213
+ def replace(other)
214
+ @entries.clear
215
+ other.each_pair do |item, count|
216
+ self.renew_count(item, count)
217
+ end
218
+ self
219
+ end
220
+
221
+ # <code>self</code>に含まれている要素数を返します。
222
+ #
223
+ # Returns number of all items in <code>self</code>.
224
+ def size
225
+ @entries.inject(0){ |sum, item| sum += item[1] }
226
+ end
227
+ alias length size
228
+
229
+ # <code>self</code>に要素がないかどうかを返します。
230
+ #
231
+ # Returns whether <code>self</code> has no item.
232
+ def empty?
233
+ @entries.empty?
234
+ end
235
+
236
+ # <code>self</code>に含まれている要素(重複は除く)からなる配列を返します。
237
+ #
238
+ # Returns an array with all items in <code>self</code>, without duplication.
239
+ def items
240
+ @entries.keys
241
+ end
242
+
243
+ # <code>self</code>の要素をすべて削除します。
244
+ # <code>self</code>を返します。
245
+ #
246
+ # Deletes all items in <code>self</code>.
247
+ # Returns <code>self</code>.
248
+ def clear
249
+ @entries.clear
250
+ self
251
+ end
252
+
253
+ # <code>item</code>が<code>self</code>中に含まれているかを返します。
254
+ #
255
+ # Returns whether <code>self</code> has <code>item</code>.
256
+ def include?(item)
257
+ @entries.has_key?(item)
258
+ end
259
+ alias member? include?
260
+
261
+ # <code>self</code>の全要素を(重複を許して)並べた文字列を返します。
262
+ # 要素間の区切りは<code>delim</code>の値を用い、
263
+ # 各要素の表示形式は与えられたブロックの返り値(なければObject#inspect)を用います。
264
+ #
265
+ # Lists all items with duplication in <code>self</code>.
266
+ # Items are deliminated with <code>delim</code>, and items are
267
+ # converted to string in the given block.
268
+ # If block is omitted, Object#inspect is used.
269
+ def listing(delim = "\n")
270
+ buf = ''
271
+ init = true
272
+ self.each do |item|
273
+ if init
274
+ init = false
275
+ else
276
+ buf += delim
277
+ end
278
+ buf += block_given? ? yield(item).to_s : item.inspect
279
+ end
280
+ buf
281
+ end
282
+
283
+ # <code>self</code>の要素と要素数の組を並べた文字列を返します。
284
+ # 要素間の区切りは<code>delim</code>の値を用い、
285
+ # 各要素の表示形式は与えられたブロックの返り値(なければObject#inspect)を用います。
286
+ #
287
+ # Lists all items without duplication and its number in <code>self</code>.
288
+ # Items are deliminated with <code>delim</code>, and items are
289
+ # converted to string in the given block.
290
+ # If block is omitted, Object#inspect is used.
291
+ def to_s(delim = "\n")
292
+ buf = ''
293
+ init = true
294
+ @entries.each_pair do |item, count|
295
+ if init
296
+ init = false
297
+ else
298
+ buf += delim
299
+ end
300
+ item_tmp = block_given? ? yield(item) : item.inspect
301
+ buf += "\##{count} #{item_tmp}"
302
+ end
303
+ buf
304
+ end
305
+
306
+ def inspect # :nodoc:
307
+ buf = "#<Multiset:"
308
+ buf += self.to_s(', ')
309
+ buf += '>'
310
+ buf
311
+ end
312
+
313
+ #--
314
+ # ============================================================
315
+ # 要素数の更新
316
+ # ============================================================
317
+ #++
318
+
319
+ # <code>self</code>中に含まれる<code>item</code>の個数を返します。
320
+ # 引数を指定しない場合は、Multiset#sizeと同じです。
321
+ # ブロックを指定することもでき、その場合は(重複しない)各要素をブロックに与え、
322
+ # 条件を満たした(結果が真であった)要素がMultiset内にいくつ入っているかを数えます。
323
+ #
324
+ # Returns number of <code>item</code>s in <code>self</code>.
325
+ # If the <code>item</code> is omitted, the value is same as Multiset#size.
326
+ # If a block is given, each element (without duplication) is given to
327
+ # the block, and returns the number of elements (including duplication)
328
+ # that returns true in the block.
329
+ #
330
+ # :call-seq:
331
+ # count(item)
332
+ # count{ |item| ... }
333
+ def count(*item_list)
334
+ if block_given?
335
+ unless item_list.empty?
336
+ raise ArgumentError, "Both item and block cannot be given"
337
+ end
338
+
339
+ result = 0
340
+ @entries.each_pair do |i, c|
341
+ result += c if yield(i)
342
+ end
343
+ result
344
+ else
345
+ case item_list.size
346
+ when 0
347
+ self.size
348
+ when 1
349
+ @entries.has_key?(item_list.first) ? @entries[item_list.first] : 0
350
+ else
351
+ raise ArgumentError, "Only one item can be given"
352
+ end
353
+ end
354
+ end
355
+
356
+ # <code>self</code>に含まれる<code>item</code>の個数を<code>number</code>個にします。
357
+ # <code>number</code>が負の数であった場合は、<code>number = 0</code>とみなします。
358
+ # 成功した場合は<code>self</code>を、失敗した場合は<code>nil</code>を返します。
359
+ #
360
+ # Sets number of <code>item</code> to <code>number</code> in <code>self</code>.
361
+ # If <code>number</code> is negative, treats as <code>number = 0</code>.
362
+ # Returns <code>self</code> if succeeded, <code>nil</code> otherwise.
363
+ def renew_count(item, number)
364
+ return nil if number == nil
365
+ n = number.to_i
366
+ if n > 0
367
+ @entries[item] = n
368
+ else
369
+ @entries.delete(item)
370
+ end
371
+ self
372
+ end
373
+
374
+ # <code>self</code>に、<code>addcount</code>個の<code>item</code>を追加します。
375
+ # 成功した場合は<code>self</code>を、失敗した場合は<code>nil</code>を返します。
376
+ #
377
+ # Adds <code>addcount</code> number of <code>item</code>s to <code>self</code>.
378
+ # Returns <code>self</code> if succeeded, or <code>nil</code> if failed.
379
+ def add(item, addcount = 1)
380
+ return nil if addcount == nil
381
+ a = addcount.to_i
382
+ return nil if a <= 0
383
+ self.renew_count(item, self.count(item) + a)
384
+ end
385
+ alias << add
386
+
387
+ # <code>self</code>から、<code>delcount</code>個の<code>item</code>を削除します。
388
+ # 成功した場合は<code>self</code>を、失敗した場合は<code>nil</code>を返します。
389
+ #
390
+ # Deletes <code>delcount</code> number of <code>item</code>s
391
+ # from <code>self</code>.
392
+ # Returns <code>self</code> if succeeded, <code>nil</code> otherwise.
393
+ def delete(item, delcount = 1)
394
+ return nil if delcount == nil || !self.include?(item)
395
+ d = delcount.to_i
396
+ return nil if d <= 0
397
+ self.renew_count(item, self.count(item) - d)
398
+ end
399
+
400
+ # <code>self</code>に含まれる<code>item</code>をすべて削除します。
401
+ # <code>self</code>を返します。
402
+ #
403
+ # Deletes all <code>item</code>s in <code>self</code>.
404
+ # Returns <code>self</code>.
405
+ def delete_all(item)
406
+ @entries.delete(item)
407
+ self
408
+ end
409
+
410
+ #--
411
+ # ============================================================
412
+ # 包含関係の比較
413
+ # ============================================================
414
+ #++
415
+
416
+ # <code>self</code>と<code>other</code>が持つすべての要素(重複なし)について
417
+ # 繰り返し、ブロックの返り値が偽であるものが存在すればその時点でfalseを返します。
418
+ # すべての要素について真であればtrueを返します。
419
+ #
420
+ # このメソッドはsuperset?、subset?、== のために定義されています。
421
+ #
422
+ # Iterates for each item in <code>self</code> and <code>other</code>,
423
+ # without duplication. If the given block returns false, then iteration
424
+ # immediately ends and returns false.
425
+ # Returns true if the given block returns true for all of iteration.
426
+ #
427
+ # This method is defined for methods superset?, subset?, ==.
428
+ def compare_set_with(other) # :nodoc: :yields: number_in_self, number_in_other
429
+ (self.items | other.items).each do |item|
430
+ return false unless yield(self.count(item), other.count(item))
431
+ end
432
+ true
433
+ end
434
+
435
+ # <code>self</code>が<code>other</code>を含んでいるかどうかを返します。
436
+ #
437
+ # Returns whether <code>self</code> is a superset of <code>other</code>.
438
+ def superset?(other)
439
+ unless other.instance_of?(Multiset)
440
+ raise ArgumentError, "Argument must be a Multiset"
441
+ end
442
+ compare_set_with(other){ |s, o| s >= o }
443
+ end
444
+
445
+ # <code>self</code>が<code>other</code>を真に含んでいるかどうかを返します。
446
+ # 「真に」とは、両者が一致する場合は含めないことを示します。
447
+ #
448
+ # Returns whether <code>self</code> is a proper superset of <code>other</code>.
449
+ def proper_superset?(other)
450
+ unless other.instance_of?(Multiset)
451
+ raise ArgumentError, "Argument must be a Multiset"
452
+ end
453
+ self.superset?(other) && self != other
454
+ end
455
+
456
+ # <code>self</code>が<code>other</code>に含まれているかどうかを返します。
457
+ #
458
+ # Returns whether <code>self</code> is a subset of <code>other</code>.
459
+ def subset?(other)
460
+ unless other.instance_of?(Multiset)
461
+ raise ArgumentError, "Argument must be a Multiset"
462
+ end
463
+ compare_set_with(other){ |s, o| s <= o }
464
+ end
465
+
466
+ # <code>self</code>が<code>other</code>に真に含まれているかどうかを返します。
467
+ # 「真に」とは、両者が一致する場合は含めないことを示します。
468
+ #
469
+ # Returns whether <code>self</code> is a proper subset of <code>other</code>.
470
+ def proper_subset?(other)
471
+ unless other.instance_of?(Multiset)
472
+ raise ArgumentError, "Argument must be a Multiset"
473
+ end
474
+ self.subset?(other) && self != other
475
+ end
476
+
477
+ # <code>self</code>が<code>other</code>と等しいかどうかを返します。
478
+ #
479
+ # Returns whether <code>self</code> is equal to <code>other</code>.
480
+ def ==(other)
481
+ return false unless other.instance_of?(Multiset)
482
+ compare_set_with(other){ |s, o| s == o }
483
+ end
484
+
485
+ #--
486
+ # ============================================================
487
+ # その他、2つのMultisetについての処理
488
+ # ============================================================
489
+ #++
490
+
491
+ # <code>self</code>と<code>other</code>の要素を合わせた多重集合を返します。
492
+ #
493
+ # Returns merged multiset of <code>self</code> and <code>other</code>.
494
+ def merge(other)
495
+ ret = self.dup
496
+ other.each_pair do |item, count|
497
+ ret.add(item, count)
498
+ end
499
+ ret
500
+ end
501
+ alias + merge
502
+
503
+ # <code>self</code>に<code>other</code>の要素を追加します。
504
+ # <code>self</code>を返します。
505
+ #
506
+ # Merges <code>other</code> to <code>self</code>.
507
+ # Returns <code>self</code>.
508
+ def merge!(other)
509
+ other.each_pair do |item, count|
510
+ self.add(item, count)
511
+ end
512
+ self
513
+ end
514
+
515
+ # <code>self</code>から<code>other</code>の要素を取り除いた多重集合を返します。
516
+ #
517
+ # Returns multiset such that items in <code>other</code> are removed from <code>self</code>.
518
+ def subtract(other)
519
+ ret = self.dup
520
+ other.each_pair do |item, count|
521
+ ret.delete(item, count)
522
+ end
523
+ ret
524
+ end
525
+ alias - subtract
526
+
527
+ # <code>self</code>から<code>other</code>の要素を削除します。
528
+ # <code>self</code>を返します。
529
+ #
530
+ # Removes items in <code>other</code> from <code>self</code>.
531
+ # Returns <code>self</code>.
532
+ def subtract!(other)
533
+ other.each_pair do |item, count|
534
+ self.delete(item, count)
535
+ end
536
+ self
537
+ end
538
+
539
+ # <code>self</code>と<code>other</code>の積集合からなる多重集合を返します。
540
+ #
541
+ # Returns intersection of <code>self</code> and <code>other</code>.
542
+ def &(other)
543
+ ret = Multiset.new
544
+ (self.items & other.items).each do |item|
545
+ ret.renew_count(item, [self.count(item), other.count(item)].min)
546
+ end
547
+ ret
548
+ end
549
+
550
+ # <code>self</code>と<code>other</code>の和集合からなる多重集合を返します。
551
+ #
552
+ # Returns union of <code>self</code> and <code>other</code>.
553
+ def |(other)
554
+ ret = self.dup
555
+ other.each_pair do |item, count|
556
+ ret.renew_count(item, [self.count(item), count].max)
557
+ end
558
+ ret
559
+ end
560
+
561
+ #--
562
+ # ============================================================
563
+ # 1つのMultisetの各要素についての処理
564
+ # ============================================================
565
+ #++
566
+
567
+ # <code>self</code>に含まれるすべての要素について繰り返します。
568
+ # <code>self</code>を返します。
569
+ # ブロックが与えられていない場合、Enumeratorを返します。
570
+ #
571
+ # このメソッドは Enumerable#each の挙動に合わせ、同じ要素を何度もブロックに
572
+ # 渡すため、効率が悪いです。Multiset#each_item, Multiset#each_pairの利用もご検討下さい。
573
+ # 例えば「"a"が100個入ったMultiset」をeachで繰り返すと100回の処理が行われますが、
574
+ # each_pairなら1回で済みます。
575
+ #
576
+ # Iterates for each item in <code>self</code>.
577
+ # Returns <code>self</code>.
578
+ # An Enumerator will be returned if no block is given.
579
+ #
580
+ # This method is ineffective since the same element in the Multiset
581
+ # can be given to the block for many times, same as the behavior of Enumerable#each.
582
+ # Please consider using Multiset#each_item or Multiset#each_pair: for example,
583
+ # a Multiset with 100 times "a" will call the given block for 100 times for Multiset#each,
584
+ # while only once for Multiset#each_pair.
585
+ def each
586
+ @entries.each_pair do |item, count|
587
+ count.times{ yield item }
588
+ end
589
+ self
590
+ end
591
+
592
+ # <code>self</code>に含まれるすべての要素について、重複を許さずに繰り返します。
593
+ # <code>self</code>を返します。
594
+ # ブロックが与えられていない場合、Enumeratorを返します。
595
+ #
596
+ # Iterates for each item in <code>self</code>, without duplication.
597
+ # Returns <code>self</code>.
598
+ # An Enumerator will be returned if no block is given.
599
+ def each_item(&block) # :yields: item
600
+ @entries.each_key(&block)
601
+ self
602
+ end
603
+
604
+ # <code>self</code>に含まれるすべての要素(重複なし)とその個数について繰り返します。
605
+ # <code>self</code>を返します。
606
+ # ブロックが与えられていない場合、Enumeratorを返します。
607
+ #
608
+ # Iterates for each pair of (non-duplicated) item and its number in <code>self</code>.
609
+ # Returns <code>self</code>.
610
+ # An Enumerator will be returned if no block is given.
611
+ def each_with_count(&block) # :yields: item, count
612
+ @entries.each_pair(&block)
613
+ self
614
+ end
615
+ alias :each_pair :each_with_count
616
+
617
+ # <code>self</code>の各要素(重複なし)をブロックに与え、返り値を集めたものからなる
618
+ # 多重集合を生成します。
619
+ #
620
+ # Gives all items in <code>self</code> (without duplication) to given block,
621
+ # and generates a new multiset whose values are returned value from the block.
622
+ def map # :yields: item
623
+ ret = Multiset.new
624
+ @entries.each_pair do |item, count|
625
+ ret.add(yield(item), count)
626
+ end
627
+ ret
628
+ end
629
+ alias collect map
630
+
631
+ # Multiset#mapと同様ですが、結果として生成される多重集合で<code>self</code>が
632
+ # 置き換えられます。<code>self</code>を返します。
633
+ #
634
+ # Same as Multiset#map, but replaces <code>self</code> by resulting multiset.
635
+ # Returns <code>self</code>.
636
+ def map!(&block) # :yields: item
637
+ self.replace(self.map(&block))
638
+ self
639
+ end
640
+ alias collect! map!
641
+
642
+ # <code>self</code>の要素(重複なし)とその個数の組をブロックに与えます。
643
+ # ブロックから2要素の配列を受け取り、前者を要素、後者をその個数とした
644
+ # 多重集合を生成します。
645
+ #
646
+ # Gives all pairs of (non-duplicate) items and their numbers in <code>self</code> to
647
+ # given block. The block must return an array of two items.
648
+ # Generates a new multiset whose values and numbers are the first and
649
+ # second item of returned array, respectively.
650
+ def map_with
651
+ ret = Multiset.new
652
+ @entries.each_pair do |item, count|
653
+ val = yield(item, count)
654
+ ret.add(val[0], val[1])
655
+ end
656
+ ret
657
+ end
658
+ alias collect_with map_with
659
+
660
+ # Multiset#map_withと同様ですが、結果として生成される多重集合で
661
+ # <code>self</code>が置き換えられます。<code>self</code>を返します。
662
+ #
663
+ # Same as Multiset#map_with, but replaces <code>self</code> by
664
+ # resulting multiset. Returns <code>self</code>.
665
+ def map_with!
666
+ self.to_hash.each_pair do |item, count|
667
+ self.delete(item, count)
668
+ val = yield(item, count)
669
+ self.add(val[0], val[1])
670
+ end
671
+ self
672
+ end
673
+ alias collect_with! map_with!
674
+
675
+ # <code>self</code>の要素を無作為に1つ選んで返します。
676
+ # すべての要素は等確率で選ばれます。
677
+ #
678
+ # Returns one item in <code>self</code> randomly.
679
+ # All items are selected with the same probability.
680
+ def sample
681
+ pos = Kernel.rand(self.size)
682
+ @entries.each_pair do |item, count|
683
+ pos -= count
684
+ return item if pos < 0
685
+ end
686
+ end
687
+ alias :rand :sample
688
+
689
+ # <code>self</code>中に含まれる多重集合を平滑化したものを返します。
690
+ #
691
+ # Generates a multiset such that multisets in <code>self</code> are flattened.
692
+ def flatten
693
+ ret = Multiset.new
694
+ self.each do |item|
695
+ if item.kind_of?(Multiset)
696
+ ret += item.flatten
697
+ else
698
+ ret << item
699
+ end
700
+ end
701
+ ret
702
+ end
703
+
704
+ # <code>self</code>中に含まれる多重集合を平滑化します。
705
+ # 平滑化した多重集合が1つでもあれば<code>self</code>を、
706
+ # そうでなければ<code>nil</code>を返します。
707
+ #
708
+ # Flattens multisets in <code>self</code>.
709
+ # Returns <code>self</code> if any item is flattened,
710
+ # <code>nil</code> otherwise.
711
+ def flatten!
712
+ ret = nil
713
+ self.to_a.each do |item|
714
+ if item.kind_of?(Multiset)
715
+ self.delete(item)
716
+ self.merge!(item.flatten)
717
+ ret = self
718
+ end
719
+ end
720
+ ret
721
+ end
722
+
723
+ # ブロックに<code>self</code>の要素(重複なし)を順次与え、
724
+ # 結果が偽であった要素のみを集めたMultisetを返します。
725
+ #
726
+ # Gives all items in <code>self</code> (without duplication) to given block,
727
+ # and returns a multiset collecting the items whose results in the block are false.
728
+ def reject
729
+ ret = Multiset.new
730
+ @entries.each_pair do |item, count|
731
+ ret.renew_count(item, count) unless yield(item)
732
+ end
733
+ ret
734
+ end
735
+
736
+ # ブロックに<code>self</code>の要素(重複なし)と個数の組を順次与え、
737
+ # 結果が偽であった要素のみを集めたMultisetを返します。
738
+ #
739
+ # Gives all pairs of (non-duplicate) items and counts in <code>self</code> to given block,
740
+ # and returns a multiset collecting the items whose results in the block are false.
741
+ def reject_with
742
+ ret = Multiset.new
743
+ @entries.each_pair do |item, count|
744
+ ret.renew_count(item, count) unless yield(item, count)
745
+ end
746
+ ret
747
+ end
748
+
749
+ # Multiset#delete_ifと同じですが、要素が1つも削除されなければ<code>nil</code>を返します。
750
+ #
751
+ # Same as Multiset#delete_if, but returns <code>nil</code> if no item is deleted.
752
+ def reject!
753
+ ret = nil
754
+ @entries.each_pair do |item, count|
755
+ if yield(item)
756
+ self.delete_all(item)
757
+ ret = self
758
+ end
759
+ end
760
+ ret
761
+ end
762
+
763
+ # ブロックに<code>self</code>の要素(重複なし)を順次与え、
764
+ # 結果が真であった要素をすべて削除します。
765
+ # <code>self</code>を返します。
766
+ #
767
+ # Gives all items in <code>self</code> (without duplication) to given block,
768
+ # and deletes that item if the block returns true.
769
+ # Returns <code>self</code>.
770
+ def delete_if
771
+ @entries.each_pair do |item, count|
772
+ self.delete_all(item) if yield(item)
773
+ end
774
+ self
775
+ end
776
+
777
+ # <code>self</code>に含まれるすべての要素(重複なし)とその個数について、
778
+ # その組をブロックに与え、結果が真であった要素をすべて削除します。
779
+ # <code>self</code>を返します。
780
+ #
781
+ # Gives each pair of (non-duplicate) item and its number to given block,
782
+ # and deletes those items if the block returns true.
783
+ # Returns <code>self</code>.
784
+ def delete_with
785
+ @entries.each_pair do |item, count|
786
+ @entries.delete(item) if yield(item, count)
787
+ end
788
+ self
789
+ end
790
+
791
+ # <code>self</code>の要素を、与えられたブロックからの返り値によって分類します。
792
+ # ブロックからの返り値をキーとして値を対応付けたMultimapを返します。
793
+ #
794
+ # Classify items in <code>self</code> by returned value from block.
795
+ # Returns a Multimap whose values are associated with keys. Keys'
796
+ # are defined by returned value from given block.
797
+ def group_by
798
+ ret = Multimap.new
799
+ @entries.each_pair do |item, count|
800
+ ret[yield(item)].add(item, count)
801
+ end
802
+ ret
803
+ end
804
+ alias :classify :group_by
805
+
806
+ # Multiset#group_byと同様ですが、ブロックには要素とその個数の組が与えられます。
807
+ #
808
+ # Same as Multiset#group_by, but the pairs of (non-duplicate) items and their counts are given to block.
809
+ def group_by_with
810
+ ret = Multimap.new
811
+ @entries.each_pair do |item, count|
812
+ ret[yield(item, count)].add(item, count)
813
+ end
814
+ ret
815
+ end
816
+ alias :classify_with :group_by_with
817
+
818
+ # ブロックに<code>self</code>の要素(重複なし)を順次与え、
819
+ # 最初に結果が真であった要素を返します。
820
+ # 見つからなかった場合は、ifnoneが指定されている場合は ifnone.call し、
821
+ # そうでなければnilを返します。
822
+ # ブロックを与えなかった場合、そのためのEnumeratorを返します。
823
+ #
824
+ # Gives all items in <code>self</code> (without duplication) to given block,
825
+ # and returns the first item that makes true the result of the block.
826
+ # If none of the items make it true, ifnone.call is executed if ifnone is specified,
827
+ # otherwise nil is returned.
828
+ # If no block is given, corresponding Enumerator is returned.
829
+ def find(ifnone = nil, &block) # :yields: item
830
+ if block
831
+ find_(ifnone, &block)
832
+ else
833
+ self.to_enum(:find_, ifnone)
834
+ end
835
+ end
836
+ alias :detect :find
837
+
838
+ def find_(ifnone, &block) # :nodoc:
839
+ @entries.each_pair do |item, count|
840
+ return item if yield(item)
841
+ end
842
+ (ifnone == nil) ? nil : ifnone.call
843
+ end
844
+ private :find_
845
+
846
+ # Multiset#findと同じですが、ブロックには<code>self</code>の要素とその個数の組が与えられます。
847
+ #
848
+ # The same as Multiset#find, but pairs of (non-duplicate) items and their counts are given to the block.
849
+ def find_with(ifnone = nil, &block) # :yields: item
850
+ if block
851
+ find_with_(ifnone, &block)
852
+ else
853
+ self.to_enum(:find_with_, ifnone)
854
+ end
855
+ end
856
+ alias :detect_with :find_with
857
+
858
+ def find_with_(ifnone, &block) # :nodoc:
859
+ @entries.each_pair do |item, count|
860
+ return item if yield(item, count)
861
+ end
862
+ (ifnone == nil) ? nil : ifnone.call
863
+ end
864
+ private :find_with_
865
+
866
+ # ブロックに<code>self</code>の要素(重複なし)を順次与え、
867
+ # 結果が真であった要素を集めた多重集合を返します。
868
+ # ブロックを与えなかった場合、そのためのEnumeratorを返します。
869
+ #
870
+ # Gives all items in <code>self</code> (without duplication) to given block,
871
+ # and returns the Multiset by items that makes true the result of the block.
872
+ # If no block is given, corresponding Enumerator is returned.
873
+ def find_all(&block) # :yields: item
874
+ if block
875
+ find_all_(&block)
876
+ else
877
+ self.to_enum(:find_all_, ifnone)
878
+ end
879
+ end
880
+ alias :select :find_all
881
+
882
+ def find_all_(&block) # :nodoc:
883
+ ret = Multiset.new
884
+ @entries.each_pair do |item, count|
885
+ ret.renew_count(item, count) if yield(item)
886
+ end
887
+ ret
888
+ end
889
+ private :find_all_
890
+
891
+ # Multiset#find_allと同じですが、ブロックには<code>self</code>の要素とその個数の組が与えられます。
892
+ #
893
+ # The same as Multiset#find_all, but pairs of (non-duplicate) items and their counts are given to the block.
894
+ def find_all_with(&block) # :yields: item
895
+ if block
896
+ find_all_with_(&block)
897
+ else
898
+ self.to_enum(:find_all_with_, ifnone)
899
+ end
900
+ end
901
+ alias :select_with :find_all_with
902
+
903
+ def find_all_with_(&block) # :nodoc:
904
+ ret = Multiset.new
905
+ @entries.each_pair do |item, count|
906
+ ret.renew_count(item, count) if yield(item, count)
907
+ end
908
+ ret
909
+ end
910
+ private :find_all_
911
+
912
+ # <code>pattern</code>の条件を満たした(<code>pattern</code> === item)要素のみを集めた多重集合を返します。
913
+ # ブロックが与えられている場合は、さらにその結果を適用した結果を返します。
914
+ #
915
+ # Collects items in <code>self</code> satisfying <code>pattern</code> (<code>pattern</code> === item).
916
+ # If a block is given, the items are converted by the result of the block.
917
+ def grep(pattern)
918
+ ret = Multiset.new
919
+ @entries.each_pair do |item, count|
920
+ if pattern === item
921
+ ret.add((block_given? ? yield(item) : item), count)
922
+ end
923
+ end
924
+ ret
925
+ end
926
+
927
+ # ブロックに「1回前のブロック呼び出しの返り値」「<code>self</code>の要素」「その個数」の
928
+ # 3つ組を順次与え、最後にブロックを呼んだ結果を返します。ただし「1回前のブロック呼び出しの返り値」は、
929
+ # 1回目のブロック呼び出しの際については、代わりに<code>init</code>の値が与えられます。
930
+ #
931
+ # Enumerable#injectと異なり、<code>init</code>は省略できません。
932
+ # またブロックの代わりにSymbolを与えることもできません。
933
+ #
934
+ # Three elements are given to the block for each (non-duplicate) items:
935
+ # the last result of the block, the item and its count.
936
+ # As for the first block call, the first argument is <code>init</code>.
937
+ # The result of the last block call is returned.
938
+ #
939
+ # Different from Enumerable#inject, <code>init</code> cannot be omitted.
940
+ # In addition, Symbol cannot be given instead of a block.
941
+ def inject_with(init)
942
+ @entries.each_pair do |item, count|
943
+ init = yield(init, item, count)
944
+ end
945
+ init
946
+ end
947
+
948
+ # 最大の要素を返します。
949
+ # 要素が存在しない場合はnilを返します。
950
+ # ブロックが与えられた場合は、要素間の大小判定を、ブロックに2つの要素を与えることで行います。
951
+ #
952
+ # Returns the largest item, or <code>nil</code> if no item is stored in <code>self</code>.
953
+ # If a block is given, their order is judged by giving two items to the block.
954
+ def max(&block) # :yields: a, b
955
+ @entries.keys.max(&block)
956
+ end
957
+
958
+ # 最小の要素を返します。
959
+ # 要素が存在しない場合はnilを返します。
960
+ # ブロックが与えられた場合は、要素間の大小判定を、ブロックに2つの要素を与えることで行います。
961
+ #
962
+ # Returns the smallest item, or <code>nil</code> if no item is stored in <code>self</code>.
963
+ # If a block is given, their order is judged by giving two items to the block.
964
+ def min(&block) # :yields: a, b
965
+ @entries.keys.min(&block)
966
+ end
967
+
968
+ # 最小の要素と最大の要素の組を返します。
969
+ # ブロックが与えられた場合は、要素間の大小判定を、ブロックに2つの要素を与えることで行います。
970
+ #
971
+ # Returns the pair consisting of the smallest and the largest item.
972
+ # If a block is given, their order is judged by giving two items to the block.
973
+ def minmax(&block) # :yields: a, b
974
+ @entries.keys.minmax(&block)
975
+ end
976
+
977
+ # ブロックの値を評価した結果が最大になるような要素を返します。
978
+ # 要素が存在しない場合はnilを返します。
979
+ #
980
+ # Returns the largest item, or <code>nil</code> if no item is stored in <code>self</code>.
981
+ def max_by(&block) # :yields: item
982
+ @entries.keys.max_by(&block)
983
+ end
984
+
985
+ # ブロックの値を評価した結果が最小になるような要素を返します。
986
+ # 要素が存在しない場合はnilを返します。
987
+ #
988
+ # Returns the smallest item, or <code>nil</code> if no item is stored in <code>self</code>.
989
+ def min_by(&block) # :yields: item
990
+ @entries.keys.min_by(&block)
991
+ end
992
+
993
+ # ブロックの値を評価した結果が最小になる要素と最大になる要素の組を返します。
994
+ # 要素が存在しない場合はnilを返します。
995
+ #
996
+ # Returns the pair consisting of the smallest and the largest item.
997
+ def minmax_by(&block) # :yields: item
998
+ @entries.keys.minmax_by(&block)
999
+ end
1000
+
1001
+ # Multiset#max と同様ですが、ブロックには「要素1」「要素1の出現数」「要素2」「要素2の出現数」の
1002
+ # 4引数が与えられます。
1003
+ #
1004
+ # Same as Multiset#max, but four arguments: "item 1", "number of item 1", "item 2" and "number of item 2" are given to the block.
1005
+ def max_with # :yields: item1, count1, item2, count2
1006
+ tmp = @entries.each_pair.max{ |a, b| yield(a[0], a[1], b[0], b[1]) }
1007
+ tmp ? tmp[0] : nil
1008
+ end
1009
+
1010
+ # Multiset#min と同様ですが、ブロックには「要素1」「要素1の出現数」「要素2」「要素2の出現数」の
1011
+ # 4引数が与えられます。
1012
+ #
1013
+ # Same as Multiset#min, but four arguments: "item 1", "number of item 1", "item 2" and "number of item 2" are given to the block.
1014
+ def min_with # :yields: item1, count1, item2, count2
1015
+ tmp = @entries.each_pair.min{ |a, b| yield(a[0], a[1], b[0], b[1]) }
1016
+ tmp ? tmp[0] : nil
1017
+ end
1018
+
1019
+ # Multiset#minmax と同様ですが、ブロックには「要素1」「要素1の出現数」「要素2」「要素2の出現数」の
1020
+ # 4引数が与えられます。
1021
+ #
1022
+ # Same as Multiset#minmax, but four arguments: "item 1", "number of item 1", "item 2" and "number of item 2" are given to the block.
1023
+ def minmax_with # :yields: item1, count1, item2, count2
1024
+ tmp = @entries.each_pair.minmax{ |a, b| yield(a[0], a[1], b[0], b[1]) }
1025
+ tmp ? [tmp[0][0], tmp[1][0]] : nil
1026
+ end
1027
+
1028
+ # Multiset#max_by と同様ですが、ブロックには要素(重複なし)とその出現数の組が与えられます。
1029
+ #
1030
+ # Same as Multiset#min, but pairs of (non-duplicated) items and their counts are given to the block.
1031
+ def max_by_with(&block) # :yields: item
1032
+ tmp = @entries.each_pair.max_by(&block)
1033
+ tmp ? tmp[0] : nil # if @entries is not empty, tmp must be a two-element array
1034
+ end
1035
+
1036
+ # Multiset#min_by と同様ですが、ブロックには要素(重複なし)とその出現数の組が与えられます。
1037
+ #
1038
+ # Same as Multiset#max, but pairs of (non-duplicated) items and their counts are given to the block.
1039
+ def min_by_with(&block) # :yields: item
1040
+ tmp = @entries.each_pair.min_by(&block)
1041
+ tmp ? tmp[0] : nil # if @entries is not empty, tmp must be a two-element array
1042
+ end
1043
+
1044
+ # Multiset#minmax_by と同様ですが、ブロックには要素(重複なし)とその出現数の組が与えられます。
1045
+ #
1046
+ # Same as Multiset#minmax, but pairs of (non-duplicated) items and their counts are given to the block.
1047
+ def minmax_by_with(&block) # :yields: item
1048
+ tmp = @entries.each_pair.minmax_by(&block)
1049
+ tmp[0] ? [tmp[0][0], tmp[1][0]] : nil
1050
+ end
1051
+
1052
+ # <code>self</code>の要素を並び替えた配列を生成します。
1053
+ #
1054
+ # Generates an array by sorting the items in <code>self</code>.
1055
+ def sort(&block) # :yields: a, b
1056
+ ret = []
1057
+ @entries.keys.sort(&block).each do |item|
1058
+ ret.fill(item, ret.length, @entries[item])
1059
+ end
1060
+ ret
1061
+ end
1062
+
1063
+ # Multiset#sortと同様ですが、ブロックには1つの要素が与えられ、その値が小さいものから順に並びます。
1064
+ #
1065
+ # Same as Multiset#sort, but only one item is given to the block.
1066
+ def sort_by(&block) # :yields: item
1067
+ ret = []
1068
+ @entries.keys.sort_by(&block).each do |item|
1069
+ ret.fill(item, ret.length, @entries[item])
1070
+ end
1071
+ ret
1072
+ end
1073
+
1074
+ # Multiset#sort と同様ですが、ブロックには「要素1」「要素1の出現数」「要素2」「要素2の出現数」の
1075
+ # 4引数が与えられます。
1076
+ #
1077
+ # Same as Multiset#sort, but four arguments: "item 1", "number of item 1", "item 2" and "number of item 2" are given to the block.
1078
+ def sort_with # :yields: item1, count1, item2, count2
1079
+ ret = []
1080
+ @entries.each_pair.sort{ |a, b| yield(a[0], a[1], b[0], b[1]) }.each do |item_count|
1081
+ ret.fill(item_count[0], ret.length, item_count[1])
1082
+ end
1083
+ ret
1084
+ end
98
1085
 
99
- require 'multiset/libmultiset'
100
- require 'multiset/libmultimap'
1086
+ # Multiset#sort_by と同様ですが、ブロックには要素(重複なし)とその出現数の組が与えられます。
1087
+ #
1088
+ # Same as Multiset#sort_by, but pairs of (non-duplicated) items and their counts are given to the block.
1089
+ def sort_by_with # :yields: item1, count1, item2, count2
1090
+ ret = []
1091
+ @entries.each_pair.sort_by{ |a| yield(*a) }.each do |item_count|
1092
+ ret.fill(item_count[0], ret.length, item_count[1])
1093
+ end
1094
+ ret
1095
+ end
1096
+ end
1097
+
1098
+ class Hash
1099
+ # <code>self</code>を多重集合に変換し、その結果を返します。
1100
+ # キーを要素、キーに対応する値をその要素の要素数とします。
1101
+ #
1102
+ # (例)<code>{:a => 4, :b => 2}.to_multiset # :aを4個、:bを2個含む多重集合</code>
1103
+ #
1104
+ # Generates multiset from <code>self</code>.
1105
+ # Keys are treated as elements, and values are number of elements
1106
+ # in the multiset. For example,
1107
+ #
1108
+ # <code>{:a => 4, :b => 2}.to_multiset # Multiset with four :a's and two :b's</code>
1109
+ def to_multiset
1110
+ ret = Multiset.new
1111
+ self.each_pair{ |item, count| ret.renew_count(item, count) }
1112
+ ret
1113
+ end
1114
+ end
101
1115
 
102
1116
  #--
103
1117
  # Sample
104
1118
  #++
105
1119
  if __FILE__ == $0
106
- puts 'Creating multisets'
107
- a = {1=>5, 4=>2, 6=>0}.to_multiset
108
- b = Multiset[1,1,4,4,6,6]
109
- p a
110
- p b
111
-
112
- puts 'Operations for multisets'
113
- p a + b
114
- p a - b
115
- p a & b
116
- p a | b
117
-
118
- puts 'Modifying multisets'
119
- p a.reject!{ |item| item == 3 }
120
- p a
121
- p a.reject!{ |item| item == 4 }
122
- p a
123
- a.add(3)
124
- a.add(4, 10)
125
- a << 1
126
- p a
127
-
128
- puts 'Flattening multisets'
129
- a = Multiset[6,6,3,4,Multiset[5,8],Multiset[6,Multiset[3,8],8],8]
130
- p a
131
- p a.flatten!
132
- p a.flatten!
1120
+ puts 'Creating multisets'
1121
+ a = {1=>5, 4=>2, 6=>0}.to_multiset
1122
+ b = Multiset[1,1,4,4,6,6]
1123
+ p a
1124
+ p b
1125
+
1126
+ puts 'Operations for multisets'
1127
+ p a + b
1128
+ p a - b
1129
+ p a & b
1130
+ p a | b
1131
+
1132
+ puts 'Modifying multisets'
1133
+ p a.reject!{ |item| item == 3 }
1134
+ p a
1135
+ p a.reject!{ |item| item == 4 }
1136
+ p a
1137
+ a.add(3)
1138
+ a.add(4, 10)
1139
+ a << 1
1140
+ p a
1141
+
1142
+ puts 'Flattening multisets'
1143
+ a = Multiset[6,6,3,4,Multiset[5,8],Multiset[6,Multiset[3,8],8],8]
1144
+ p a
1145
+ p a.flatten!
1146
+ p a.flatten!
133
1147
  end