multiset 0.3.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/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/lib/multiset.rb +133 -0
- data/lib/multiset/libmultimap.rb +475 -0
- data/lib/multiset/libmultiset.rb +757 -0
- data/multiset.gemspec +66 -0
- data/spec/multiset_spec.rb +12 -0
- data/spec/multiset_spec_ported.rb +528 -0
- data/spec/spec_helper.rb +12 -0
- metadata +144 -0
@@ -0,0 +1,757 @@
|
|
1
|
+
#==概要(Basic information)
|
2
|
+
#
|
3
|
+
#Rubyによる多重集合(マルチセット)の実装です。
|
4
|
+
#通常の集合(Rubyでは"set"ライブラリ)と異なり、多重集合は
|
5
|
+
#同一の要素を複数格納することができます。
|
6
|
+
#
|
7
|
+
#メソッド名は基本的にSetクラスに合わせてあります。またSetクラスが持つ
|
8
|
+
#メソッドの大部分を実装していますが、いくつか未実装なものもあります。
|
9
|
+
#
|
10
|
+
#Ruby implementation of multiset.
|
11
|
+
#Unlike ordinary set(see Ruby documentation for "set" library),
|
12
|
+
#multiset can contain two or more same items.
|
13
|
+
#
|
14
|
+
#Most methods' names are same as those of Set class, and all other than
|
15
|
+
#a few methods in Set class is implemented on Multiset class.
|
16
|
+
#
|
17
|
+
#* <code>Set[:a,:b,:c,:b,:b,:c] => #<Set: {:b, :c, :a}></code>
|
18
|
+
#* <code>Multiset[:a,:b,:c,:b,:b,:c] => #<Multiset:<tt>#</tt>3 :b, <tt>#</tt>2 :c, <tt>#</tt>1 :a></code>
|
19
|
+
|
20
|
+
class Multiset
|
21
|
+
include Enumerable
|
22
|
+
@@parse_string = true
|
23
|
+
|
24
|
+
#--
|
25
|
+
# Constructors
|
26
|
+
#++
|
27
|
+
|
28
|
+
# <code>list</code>に含まれる要素からなる多重集合を生成します。
|
29
|
+
# <code>list</code>を省略した場合、空の多重集合を生成します。
|
30
|
+
#
|
31
|
+
# <code>list</code>には<code>Enumerable</code>であるオブジェクトのみ
|
32
|
+
# 指定できます。そうでない場合、例外<code>ArgumentError</code>が
|
33
|
+
# 発生します。
|
34
|
+
#
|
35
|
+
# Generates a multiset from items in <code>list</code>.
|
36
|
+
# If <code>list</code> is omitted, returns empty multiset.
|
37
|
+
#
|
38
|
+
# <code>list</code> must be <code>Enumerable</code>. If not,
|
39
|
+
# <code>ArgumentError</code> is raised.
|
40
|
+
def initialize(list = nil)
|
41
|
+
@items = {}
|
42
|
+
if list.kind_of?(Enumerable)
|
43
|
+
list.each{ |item| add item }
|
44
|
+
elsif list != nil
|
45
|
+
raise ArgumentError, "Item list must include 'Enumerable' module"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# <code>list</code>に含まれる要素からなる多重集合を生成します。
|
50
|
+
# <code>new</code>を用いる場合と異なり、引数の1つ1つが多重集合の要素になります。
|
51
|
+
#
|
52
|
+
# 主に多重集合のリテラルを生成するのに用います。
|
53
|
+
#
|
54
|
+
# Generates a multiset from items in <code>list</code>.
|
55
|
+
# Unlike using <code>new</code>, each argument is one item in generated multiset.
|
56
|
+
#
|
57
|
+
# This method is mainly used when you generate literal of multiset.
|
58
|
+
def Multiset.[](*list)
|
59
|
+
Multiset.new(list)
|
60
|
+
end
|
61
|
+
|
62
|
+
# <code>object</code>を多重集合に変換し生成します。
|
63
|
+
# * <code>object</code>がMultisetのインスタンスである場合、
|
64
|
+
# その複製を返します。
|
65
|
+
# * <code>object</code>がMultisetのインスタンスでなく、
|
66
|
+
# かつ<code>each_pair</code>メソッドを持っている場合、
|
67
|
+
# <code>each_pair</code>から渡される2つの引数について、前者を要素、
|
68
|
+
# 後者をその個数とした多重集合を生成します。Hash#to_multisetも
|
69
|
+
# ご覧下さい。
|
70
|
+
# * <code>object</code>が<code>each_pair</code>メソッドを持っておらず、
|
71
|
+
# かつ<code>Enumerable</code>である場合は、Multiset#newと同じ結果です。
|
72
|
+
# * それ以外の場合は、例外<code>ArgumentError</code>が発生します。
|
73
|
+
#
|
74
|
+
# Generates a multiset converting <code>object</code>.
|
75
|
+
# * If <code>object</code> is an instance of Multiset, returns
|
76
|
+
# duplicated <code>object</code>.
|
77
|
+
# * If <code>object</code> is not an instance of Multiset and has
|
78
|
+
# the method <code>each_pair</code>,
|
79
|
+
# for each pair of two arguments from <code>each_pair</code>,
|
80
|
+
# first argument becomes item in multiset and second argument
|
81
|
+
# becomes its number. See also Hash#to_multiset .
|
82
|
+
# * If <code>object</code> does not have the method <code>each_pair</code>
|
83
|
+
# and <code>object</code> includes <code>Enumerable</code>, this method
|
84
|
+
# results equal to Multiset#new .
|
85
|
+
# * Otherwise, <code>ArgumentError</code> is raised.
|
86
|
+
def Multiset.parse(object)
|
87
|
+
if !@@parse_string && object.kind_of?(String)
|
88
|
+
raise ArgumentError, "Multiset.parse can not parse strings"
|
89
|
+
end
|
90
|
+
Multiset.parse_force(object)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Multiset.parseと同様ですが、挙動がMultiset.parse_stringの設定に
|
94
|
+
# 影響されません(<code>Multiset.parse_string(true)</code>の場合と
|
95
|
+
# 同様とみなします)。
|
96
|
+
#
|
97
|
+
# Same as Multiset.parse, but this method is not affected
|
98
|
+
# by the setting of Multiset.parse_string (treats
|
99
|
+
# <code>Multiset.parse_string(true)</code>) .
|
100
|
+
def Multiset.parse_force(object)
|
101
|
+
if object.instance_of?(Multiset)
|
102
|
+
ret = object.dup
|
103
|
+
else
|
104
|
+
ret = Multiset.new
|
105
|
+
if defined? object.each_pair
|
106
|
+
object.each_pair{ |item, count| ret.add item, count }
|
107
|
+
elsif object.kind_of?(Enumerable)
|
108
|
+
object.each{ |item| ret.add item }
|
109
|
+
else
|
110
|
+
raise ArgumentError, "Source of Multiset must have 'each_pair' method or include 'Enumerable' module"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
ret
|
114
|
+
end
|
115
|
+
|
116
|
+
# Multiset.parseの引数にStringを渡すことを許すか指定します。
|
117
|
+
#
|
118
|
+
# StringはEnumerableなので、Multiset.parseでは引数として文字列を
|
119
|
+
# 渡すこともできます。しかしこれはバグの危険性があるため、
|
120
|
+
# このメソッドで禁止することができます。
|
121
|
+
#
|
122
|
+
# <code>boolean</code>にはtrueおよびfalseが指定できます。
|
123
|
+
# falseを設定した場合、Multiset.parseやMultimap#[]=などで
|
124
|
+
# 文字列を直接指定した場合に<code>ArgumentError</code>が発生します。
|
125
|
+
# デフォルト値は<code>true</code>です。
|
126
|
+
#
|
127
|
+
# <code>boolean</code>を省略した場合は、現在のこの値がtrueか
|
128
|
+
# falseかを返します。
|
129
|
+
#
|
130
|
+
# この値はクラス変数で管理されているので、一度変更するとすべての
|
131
|
+
# インスタンスに影響が及びます。
|
132
|
+
#
|
133
|
+
# Allows or prohibits Strings from being arguments of Multiset.parse .
|
134
|
+
#
|
135
|
+
# String includes module Enumerable, therefore you can give a string as
|
136
|
+
# an argument of Multiset.parse . But this may cause bugs,
|
137
|
+
# so you can prohibit this.
|
138
|
+
#
|
139
|
+
# <code>boolean</code> can be true or false. If this value is false,
|
140
|
+
# <code>ArgumentError</code> is raised whenever you specify a string
|
141
|
+
# as an argument of Multiset.parse , Multimap#[]= , and so on.
|
142
|
+
# This value is <code>true</code> by default.
|
143
|
+
#
|
144
|
+
# If <code>boolean</code> is not specified, returns current value
|
145
|
+
# (true or false).
|
146
|
+
#
|
147
|
+
# This value is stored in class variable, therefore this value has
|
148
|
+
# effect for all instances of Multiset.
|
149
|
+
def Multiset.parse_string(boolean = nil)
|
150
|
+
case boolean
|
151
|
+
when true, false
|
152
|
+
@@parse_string = boolean
|
153
|
+
when nil
|
154
|
+
else
|
155
|
+
raise ArgumentError, "Argument must be true or false"
|
156
|
+
end
|
157
|
+
@@parse_string
|
158
|
+
end
|
159
|
+
|
160
|
+
# Same as Multiset.parse_string
|
161
|
+
def Multiset.parse_string?(boolean = nil)
|
162
|
+
Multiset.parse_string boolean
|
163
|
+
end
|
164
|
+
|
165
|
+
# <code>self</code>の複製を生成して返します。
|
166
|
+
#
|
167
|
+
# Returns duplicated <code>self</code>.
|
168
|
+
def dup
|
169
|
+
@items.to_multiset
|
170
|
+
end
|
171
|
+
|
172
|
+
# <code>self</code>を<code>Hash</code>に変換して返します。
|
173
|
+
# 生成されるハッシュの構造については、Hash#to_multisetをご覧下さい。
|
174
|
+
#
|
175
|
+
# Converts <code>self</code> to a <code>Hash</code>.
|
176
|
+
# See Hash#to_multiset about format of generated hash.
|
177
|
+
def to_hash
|
178
|
+
@items.dup
|
179
|
+
end
|
180
|
+
|
181
|
+
# <code>self</code>を通常の集合(Ruby標準添付の<code>Set</code>)に
|
182
|
+
# 変換したものを返します。
|
183
|
+
#
|
184
|
+
# このメソッドを呼び出すと、<code>require "set"</code>が行われます。
|
185
|
+
#
|
186
|
+
# なおSetをMultisetに変換するには、<code>Multiset.new(instance_of_set)</code>で
|
187
|
+
# 可能です。
|
188
|
+
#
|
189
|
+
# Converts <code>self</code> to ordinary set
|
190
|
+
# (The <code>Set</code> class attached to Ruby by default).
|
191
|
+
#
|
192
|
+
# <code>require "set"</code> is performed when this method is called.
|
193
|
+
#
|
194
|
+
# To convert Set to Multiset, use <code>Multiset.new(instance_of_set)</code>.
|
195
|
+
def to_set
|
196
|
+
require "set"
|
197
|
+
Set.new(@items.keys)
|
198
|
+
end
|
199
|
+
|
200
|
+
# <code>self</code>を配列に変換して返します。
|
201
|
+
#
|
202
|
+
# Converts <code>self</code> to an array.
|
203
|
+
def to_a
|
204
|
+
ret = []
|
205
|
+
@items.each_pair do |item, count|
|
206
|
+
ret.concat Array.new(count, item)
|
207
|
+
end
|
208
|
+
ret
|
209
|
+
end
|
210
|
+
|
211
|
+
def hash # :nodoc:
|
212
|
+
val = 0
|
213
|
+
@items.each_pair do |item, count|
|
214
|
+
val += item.hash * count
|
215
|
+
end
|
216
|
+
val
|
217
|
+
end
|
218
|
+
|
219
|
+
def eql?(other) # :nodoc:
|
220
|
+
if self.hash == other.hash
|
221
|
+
self == other
|
222
|
+
else
|
223
|
+
false
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# <code>self</code>の内容を<code>other</code>のものに置き換えます。
|
228
|
+
# <code>self</code>を返します。
|
229
|
+
#
|
230
|
+
# Replaces <code>self</code> by <code>other</code>.
|
231
|
+
# Returns <code>self</code>.
|
232
|
+
def replace(other)
|
233
|
+
@items.clear
|
234
|
+
other.each_pair do |item, count|
|
235
|
+
self.renew_count(item, count)
|
236
|
+
end
|
237
|
+
self
|
238
|
+
end
|
239
|
+
|
240
|
+
# <code>self</code>に含まれている要素数を返します。
|
241
|
+
#
|
242
|
+
# Returns number of all items in <code>self</code>.
|
243
|
+
def size
|
244
|
+
@items.inject(0){ |sum, item| sum += item[1] }
|
245
|
+
end
|
246
|
+
alias length size
|
247
|
+
|
248
|
+
# <code>self</code>に要素がないかどうかを返します。
|
249
|
+
#
|
250
|
+
# Returns whether <code>self</code> has no item.
|
251
|
+
def empty?
|
252
|
+
@items.empty?
|
253
|
+
end
|
254
|
+
|
255
|
+
# <code>self</code>に含まれている要素(重複は除く)からなる配列を返します。
|
256
|
+
#
|
257
|
+
# Returns an array with all items in <code>self</code>, without duplication.
|
258
|
+
def items
|
259
|
+
@items.keys
|
260
|
+
end
|
261
|
+
|
262
|
+
# <code>self</code>の要素をすべて削除します。
|
263
|
+
# <code>self</code>を返します。
|
264
|
+
#
|
265
|
+
# Deletes all items in <code>self</code>.
|
266
|
+
# Returns <code>self</code>.
|
267
|
+
def clear
|
268
|
+
@items.clear
|
269
|
+
self
|
270
|
+
end
|
271
|
+
|
272
|
+
# <code>item</code>が<code>self</code>中に含まれているかを返します。
|
273
|
+
#
|
274
|
+
# Returns whether <code>self</code> has <code>item</code>.
|
275
|
+
def include?(item)
|
276
|
+
@items.has_key?(item)
|
277
|
+
end
|
278
|
+
alias member? include?
|
279
|
+
|
280
|
+
# <code>self</code>中に含まれる<code>item</code>の個数を返します。
|
281
|
+
#
|
282
|
+
# Returns number of <code>item</code>s in <code>self</code>.
|
283
|
+
def count(item)
|
284
|
+
@items.has_key?(item) ? @items[item] : 0
|
285
|
+
end
|
286
|
+
|
287
|
+
# <code>self</code>に含まれるすべての要素について繰り返します。
|
288
|
+
# <code>self</code>を返します。
|
289
|
+
#
|
290
|
+
# Iterates for each item in <code>self</code>.
|
291
|
+
# Returns <code>self</code>.
|
292
|
+
def each
|
293
|
+
@items.each_pair do |item, count|
|
294
|
+
count.times{ yield item }
|
295
|
+
end
|
296
|
+
self
|
297
|
+
end
|
298
|
+
|
299
|
+
# <code>self</code>に含まれるすべての要素について、重複を許さずに繰り返します。
|
300
|
+
# <code>self</code>を返します。
|
301
|
+
#
|
302
|
+
# Iterates for each item in <code>self</code>, without duplication.
|
303
|
+
# Returns <code>self</code>.
|
304
|
+
def each_item(&block) # :yields: item
|
305
|
+
@items.each_key(&block)
|
306
|
+
self
|
307
|
+
end
|
308
|
+
|
309
|
+
# <code>self</code>に含まれるすべての要素とその個数について繰り返します。
|
310
|
+
# <code>self</code>を返します。
|
311
|
+
#
|
312
|
+
# Iterates for each pair of item and its number in <code>self</code>.
|
313
|
+
# Returns <code>self</code>.
|
314
|
+
def each_pair(&block) # :yields: item, count
|
315
|
+
@items.each_pair(&block)
|
316
|
+
self
|
317
|
+
end
|
318
|
+
|
319
|
+
# <code>self</code>に含まれる<code>item</code>の個数を<code>number</code>個にします。
|
320
|
+
# <code>number</code>が負の数であった場合は、<code>number = 0</code>とみなします。
|
321
|
+
# 成功した場合は<code>self</code>を、失敗した場合は<code>nil</code>を返します。
|
322
|
+
#
|
323
|
+
# Sets number of <code>item</code> to <code>number</code> in <code>self</code>.
|
324
|
+
# If <code>number</code> is negative, treats as <code>number = 0</code>.
|
325
|
+
# Returns <code>self</code> if succeeded, <code>nil</code> otherwise.
|
326
|
+
def renew_count(item, number)
|
327
|
+
return nil if number == nil
|
328
|
+
n = number.to_i
|
329
|
+
if n > 0
|
330
|
+
@items[item] = n
|
331
|
+
else
|
332
|
+
@items.delete(item)
|
333
|
+
end
|
334
|
+
self
|
335
|
+
end
|
336
|
+
|
337
|
+
# <code>self</code>の各要素をブロックに与え、返り値を集めたものからなる
|
338
|
+
# 多重集合を生成します。
|
339
|
+
#
|
340
|
+
# Gives all items in <code>self</code> to given block,
|
341
|
+
# and generates a new multiset whose values are returned value from the block.
|
342
|
+
def map
|
343
|
+
ret = Multiset.new
|
344
|
+
self.each do |item|
|
345
|
+
ret << yield(item)
|
346
|
+
end
|
347
|
+
ret
|
348
|
+
end
|
349
|
+
alias collect map
|
350
|
+
|
351
|
+
# Multiset#mapと同様ですが、結果として生成される多重集合で<code>self</code>が
|
352
|
+
# 置き換えられます。<code>self</code>を返します。
|
353
|
+
#
|
354
|
+
# Same as Multiset#map, but replaces <code>self</code> by resulting multiset.
|
355
|
+
# Returns <code>self</code>.
|
356
|
+
def map!
|
357
|
+
self.to_a.each do |item|
|
358
|
+
self.delete(item)
|
359
|
+
self << yield(item)
|
360
|
+
end
|
361
|
+
self
|
362
|
+
end
|
363
|
+
alias collect! map!
|
364
|
+
|
365
|
+
# <code>self</code>の要素とその個数の組をブロックに与えます。
|
366
|
+
# ブロックから2要素の配列を受け取り、前者を要素、後者をその個数とした
|
367
|
+
# 多重集合を生成します。
|
368
|
+
#
|
369
|
+
# Gives all pairs of items and their numbers in <code>self</code> to
|
370
|
+
# given block. The block must return an array of two items.
|
371
|
+
# Generates a new multiset whose values and numbers are the first and
|
372
|
+
# second item of returned array, respectively.
|
373
|
+
def map_with
|
374
|
+
ret = Multiset.new
|
375
|
+
self.each_pair do |item, count|
|
376
|
+
val = yield(item, count)
|
377
|
+
ret.add(val[0], val[1])
|
378
|
+
end
|
379
|
+
ret
|
380
|
+
end
|
381
|
+
alias collect_with map_with
|
382
|
+
|
383
|
+
# Multiset#map_withと同様ですが、結果として生成される多重集合で
|
384
|
+
# <code>self</code>が置き換えられます。<code>self</code>を返します。
|
385
|
+
#
|
386
|
+
# Same as Multiset#map_with, but replaces <code>self</code> by
|
387
|
+
# resulting multiset. Returns <code>self</code>.
|
388
|
+
def map_with!
|
389
|
+
self.to_hash.each_pair do |item, count|
|
390
|
+
self.delete(item, count)
|
391
|
+
val = yield(item, count)
|
392
|
+
self.add(val[0], val[1])
|
393
|
+
end
|
394
|
+
self
|
395
|
+
end
|
396
|
+
alias collect_with! map_with!
|
397
|
+
|
398
|
+
# <code>self</code>の要素を無作為に1つ選んで返します。
|
399
|
+
# すべての要素は等確率で選ばれます。
|
400
|
+
#
|
401
|
+
# Returns one item in <code>self</code> randomly.
|
402
|
+
# All items are selected with same probability.
|
403
|
+
def rand
|
404
|
+
pos = Kernel.rand(self.size)
|
405
|
+
@items.each_pair do |item, count|
|
406
|
+
pos -= count
|
407
|
+
return item if pos < 0
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
# <code>self</code>と<code>other</code>が持つすべての要素(重複なし)について
|
412
|
+
# 繰り返し、ブロックの返り値が偽であるものが存在すればその時点でfalseを返します。
|
413
|
+
# すべての要素について真であればtrueを返します。
|
414
|
+
#
|
415
|
+
# このメソッドはsuperset?、subset?、== のために定義されています。
|
416
|
+
#
|
417
|
+
# Iterates for each item in <code>self</code> and <code>other</code>,
|
418
|
+
# without duplication. If the given block returns false, then iteration
|
419
|
+
# immediately ends and returns false.
|
420
|
+
# Returns true if the given block returns true for all of iteration.
|
421
|
+
#
|
422
|
+
# This method is defined for methods superset?, subset?, ==.
|
423
|
+
def compare_set_with(other) # :nodoc: :yields: number_in_self, number_in_other
|
424
|
+
check = self.items.dup
|
425
|
+
check.concat(other.items)
|
426
|
+
check.each do |item|
|
427
|
+
return false unless yield(self.count(item), other.count(item))
|
428
|
+
end
|
429
|
+
true
|
430
|
+
end
|
431
|
+
|
432
|
+
# <code>self</code>が<code>other</code>を含んでいるかどうかを返します。
|
433
|
+
#
|
434
|
+
# Returns whether <code>self</code> is a superset of <code>other</code>.
|
435
|
+
def superset?(other)
|
436
|
+
unless other.instance_of?(Multiset)
|
437
|
+
raise ArgumentError, "Argument must be a Multiset"
|
438
|
+
end
|
439
|
+
compare_set_with(other){ |s, o| s >= o }
|
440
|
+
end
|
441
|
+
|
442
|
+
# <code>self</code>が<code>other</code>を真に含んでいるかどうかを返します。
|
443
|
+
# 「真に」とは、両者が一致する場合は含めないことを示します。
|
444
|
+
#
|
445
|
+
# Returns whether <code>self</code> is a proper superset of <code>other</code>.
|
446
|
+
def proper_superset?(other)
|
447
|
+
unless other.instance_of?(Multiset)
|
448
|
+
raise ArgumentError, "Argument must be a Multiset"
|
449
|
+
end
|
450
|
+
self.superset?(other) && self != other
|
451
|
+
end
|
452
|
+
|
453
|
+
# <code>self</code>が<code>other</code>に含まれているかどうかを返します。
|
454
|
+
#
|
455
|
+
# Returns whether <code>self</code> is a subset of <code>other</code>.
|
456
|
+
def subset?(other)
|
457
|
+
unless other.instance_of?(Multiset)
|
458
|
+
raise ArgumentError, "Argument must be a Multiset"
|
459
|
+
end
|
460
|
+
compare_set_with(other){ |s, o| s <= o }
|
461
|
+
end
|
462
|
+
|
463
|
+
# <code>self</code>が<code>other</code>に真に含まれているかどうかを返します。
|
464
|
+
# 「真に」とは、両者が一致する場合は含めないことを示します。
|
465
|
+
#
|
466
|
+
# Returns whether <code>self</code> is a proper subset of <code>other</code>.
|
467
|
+
def proper_subset?(other)
|
468
|
+
unless other.instance_of?(Multiset)
|
469
|
+
raise ArgumentError, "Argument must be a Multiset"
|
470
|
+
end
|
471
|
+
self.subset?(other) && self != other
|
472
|
+
end
|
473
|
+
|
474
|
+
# <code>self</code>が<code>other</code>と等しいかどうかを返します。
|
475
|
+
#
|
476
|
+
# Returns whether <code>self</code> is equal to <code>other</code>.
|
477
|
+
def ==(other)
|
478
|
+
return false unless other.instance_of?(Multiset)
|
479
|
+
compare_set_with(other){ |s, o| s == o }
|
480
|
+
end
|
481
|
+
|
482
|
+
# <code>self</code>中に含まれる多重集合を平滑化したものを返します。
|
483
|
+
#
|
484
|
+
# Generates a multiset such that multisets in <code>self</code> are flattened.
|
485
|
+
def flatten
|
486
|
+
ret = Multiset.new
|
487
|
+
self.each do |item|
|
488
|
+
if item.kind_of?(Multiset)
|
489
|
+
ret += item.flatten
|
490
|
+
else
|
491
|
+
ret << item
|
492
|
+
end
|
493
|
+
end
|
494
|
+
ret
|
495
|
+
end
|
496
|
+
|
497
|
+
# <code>self</code>中に含まれる多重集合を平滑化します。
|
498
|
+
# 平滑化した多重集合が1つでもあれば<code>self</code>を、
|
499
|
+
# そうでなければ<code>nil</code>を返します。
|
500
|
+
#
|
501
|
+
# Flattens multisets in <code>self</code>.
|
502
|
+
# Returns <code>self</code> if any item is flattened,
|
503
|
+
# <code>nil</code> otherwise.
|
504
|
+
def flatten!
|
505
|
+
ret = nil
|
506
|
+
self.to_a.each do |item|
|
507
|
+
if item.kind_of?(Multiset)
|
508
|
+
self.delete(item)
|
509
|
+
self.merge!(item.flatten)
|
510
|
+
ret = self
|
511
|
+
end
|
512
|
+
end
|
513
|
+
ret
|
514
|
+
end
|
515
|
+
|
516
|
+
# <code>self</code>に、<code>addcount</code>個の<code>item</code>を追加します。
|
517
|
+
# 成功した場合は<code>self</code>を、失敗した場合は<code>nil</code>を返します。
|
518
|
+
#
|
519
|
+
# Adds <code>addcount</code> number of <code>item</code>s to <code>self</code>.
|
520
|
+
# Returns <code>self</code> if succeeded, or <code>nil</code> if failed.
|
521
|
+
def add(item, addcount = 1)
|
522
|
+
return nil if addcount == nil
|
523
|
+
a = addcount.to_i
|
524
|
+
return nil if a <= 0
|
525
|
+
self.renew_count(item, self.count(item) + a)
|
526
|
+
end
|
527
|
+
alias << add
|
528
|
+
|
529
|
+
# <code>self</code>から、<code>delcount</code>個の<code>item</code>を削除します。
|
530
|
+
# 成功した場合は<code>self</code>を、失敗した場合は<code>nil</code>を返します。
|
531
|
+
#
|
532
|
+
# Deletes <code>delcount</code> number of <code>item</code>s
|
533
|
+
# from <code>self</code>.
|
534
|
+
# Returns <code>self</code> if succeeded, <code>nil</code> otherwise.
|
535
|
+
def delete(item, delcount = 1)
|
536
|
+
return nil if delcount == nil || !self.include?(item)
|
537
|
+
d = delcount.to_i
|
538
|
+
return nil if d <= 0
|
539
|
+
self.renew_count(item, self.count(item) - d)
|
540
|
+
end
|
541
|
+
|
542
|
+
# <code>self</code>に含まれる<code>item</code>をすべて削除します。
|
543
|
+
# <code>self</code>を返します。
|
544
|
+
#
|
545
|
+
# Deletes all <code>item</code>s in <code>self</code>.
|
546
|
+
# Returns <code>self</code>.
|
547
|
+
def delete_all(item)
|
548
|
+
@items.delete(item)
|
549
|
+
self
|
550
|
+
end
|
551
|
+
|
552
|
+
# delete_ifと同じですが、要素が1つも削除されなければ<code>nil</code>を返します。
|
553
|
+
#
|
554
|
+
# Same as delete_if, but returns <code>nil</code> if no item is deleted.
|
555
|
+
def reject!
|
556
|
+
ret = nil
|
557
|
+
self.to_a.each do |item|
|
558
|
+
if yield(item)
|
559
|
+
ret = self if self.delete(item) == self
|
560
|
+
end
|
561
|
+
end
|
562
|
+
ret
|
563
|
+
end
|
564
|
+
|
565
|
+
# ブロックに<code>self</code>の要素を順次与え、
|
566
|
+
# 結果が真であった要素をすべて削除します。
|
567
|
+
# <code>self</code>を返します。
|
568
|
+
#
|
569
|
+
# Gives all items in <code>self</code> to given block,
|
570
|
+
# and deletes that item if the block returns true.
|
571
|
+
# Returns <code>self</code>.
|
572
|
+
def delete_if
|
573
|
+
self.to_a.each do |item|
|
574
|
+
@items.delete(item) if yield(item)
|
575
|
+
end
|
576
|
+
self
|
577
|
+
end
|
578
|
+
|
579
|
+
# <code>self</code>に含まれるすべての要素とその個数について、
|
580
|
+
# その組をブロックに与え、結果が真であった要素をすべて削除します。
|
581
|
+
# <code>self</code>を返します。
|
582
|
+
#
|
583
|
+
# Gives each pair of item and its number to given block,
|
584
|
+
# and deletes those items if the block returns true.
|
585
|
+
# Returns <code>self</code>.
|
586
|
+
def delete_with
|
587
|
+
@items.each_pair do |item, count|
|
588
|
+
@items.delete(item) if yield(item, count)
|
589
|
+
end
|
590
|
+
self
|
591
|
+
end
|
592
|
+
|
593
|
+
# <code>self</code>と<code>other</code>の要素を合わせた多重集合を返します。
|
594
|
+
#
|
595
|
+
# Returns merged multiset of <code>self</code> and <code>other</code>.
|
596
|
+
def merge(other)
|
597
|
+
ret = self.dup
|
598
|
+
other.each_pair do |item, count|
|
599
|
+
ret.add(item, count)
|
600
|
+
end
|
601
|
+
ret
|
602
|
+
end
|
603
|
+
alias + merge
|
604
|
+
|
605
|
+
# <code>self</code>に<code>other</code>の要素を追加します。
|
606
|
+
# <code>self</code>を返します。
|
607
|
+
#
|
608
|
+
# Merges <code>other</code> to <code>self</code>.
|
609
|
+
# Returns <code>self</code>.
|
610
|
+
def merge!(other)
|
611
|
+
other.each_pair do |item, count|
|
612
|
+
self.add(item, count)
|
613
|
+
end
|
614
|
+
self
|
615
|
+
end
|
616
|
+
|
617
|
+
# <code>self</code>から<code>other</code>の要素を取り除いた多重集合を返します。
|
618
|
+
#
|
619
|
+
# Returns multiset such that items in <code>other</code> are removed from <code>self</code>.
|
620
|
+
def subtract(other)
|
621
|
+
ret = self.dup
|
622
|
+
other.each_pair do |item, count|
|
623
|
+
ret.delete(item, count)
|
624
|
+
end
|
625
|
+
ret
|
626
|
+
end
|
627
|
+
alias - subtract
|
628
|
+
|
629
|
+
# <code>self</code>から<code>other</code>の要素を削除します。
|
630
|
+
# <code>self</code>を返します。
|
631
|
+
#
|
632
|
+
# Removes items in <code>other</code> from <code>self</code>.
|
633
|
+
# Returns <code>self</code>.
|
634
|
+
def subtract!(other)
|
635
|
+
other.each_pair do |item, count|
|
636
|
+
self.delete(item, count)
|
637
|
+
end
|
638
|
+
self
|
639
|
+
end
|
640
|
+
|
641
|
+
# <code>self</code>と<code>other</code>の積集合からなる多重集合を返します。
|
642
|
+
#
|
643
|
+
# Returns intersection of <code>self</code> and <code>other</code>.
|
644
|
+
def &(other)
|
645
|
+
ret = Multiset.new
|
646
|
+
(self.items & other.items).each do |item|
|
647
|
+
ret.renew_count(item, [self.count(item), other.count(item)].min)
|
648
|
+
end
|
649
|
+
ret
|
650
|
+
end
|
651
|
+
|
652
|
+
# <code>self</code>と<code>other</code>の和集合からなる多重集合を返します。
|
653
|
+
#
|
654
|
+
# Returns union of <code>self</code> and <code>other</code>.
|
655
|
+
def |(other)
|
656
|
+
ret = self.dup
|
657
|
+
other.each_pair do |item, count|
|
658
|
+
ret.renew_count(item, [self.count(item), count].max)
|
659
|
+
end
|
660
|
+
ret
|
661
|
+
end
|
662
|
+
|
663
|
+
# <code>self</code>の要素を、与えられたブロックからの返り値によって分類します。
|
664
|
+
# ブロックからの返り値をキーとして値を対応付けたMultimapを返します。
|
665
|
+
#
|
666
|
+
# Classify items in <code>self</code> by returned value from block.
|
667
|
+
# Returns a Multimap whose values are associated with keys. Keys'
|
668
|
+
# are defined by returned value from given block.
|
669
|
+
def classify
|
670
|
+
ret = Multimap.new
|
671
|
+
self.each do |item|
|
672
|
+
ret[yield(item)].add(item)
|
673
|
+
end
|
674
|
+
ret
|
675
|
+
end
|
676
|
+
|
677
|
+
# classifyと同様ですが、ブロックには要素とその個数の組が与えられます。
|
678
|
+
#
|
679
|
+
# Same as classify, but the pair of item and its number is given to block.
|
680
|
+
def classify_with
|
681
|
+
ret = Multimap.new
|
682
|
+
self.each_pair do |item, count|
|
683
|
+
ret[yield(item, count)].add(item, count)
|
684
|
+
end
|
685
|
+
ret
|
686
|
+
end
|
687
|
+
|
688
|
+
# <code>self</code>の全要素を(重複を許して)並べた文字列を返します。
|
689
|
+
# 要素間の区切りは<code>delim</code>の値を用い、
|
690
|
+
# 各要素の表示形式は与えられたブロックの返り値(なければObject#inspect)を用います。
|
691
|
+
#
|
692
|
+
# Lists all items with duplication in <code>self</code>.
|
693
|
+
# Items are deliminated with <code>delim</code>, and items are
|
694
|
+
# converted to string in the given block.
|
695
|
+
# If block is omitted, Object#inspect is used.
|
696
|
+
def listing(delim = "\n")
|
697
|
+
buf = ''
|
698
|
+
init = true
|
699
|
+
self.each do |item|
|
700
|
+
if init
|
701
|
+
init = false
|
702
|
+
else
|
703
|
+
buf += delim
|
704
|
+
end
|
705
|
+
buf += block_given? ? yield(item).to_s : item.inspect
|
706
|
+
end
|
707
|
+
buf
|
708
|
+
end
|
709
|
+
|
710
|
+
# <code>self</code>の要素と要素数の組を並べた文字列を返します。
|
711
|
+
# 要素間の区切りは<code>delim</code>の値を用い、
|
712
|
+
# 各要素の表示形式は与えられたブロックの返り値(なければObject#inspect)を用います。
|
713
|
+
#
|
714
|
+
# Lists all items without duplication and its number in <code>self</code>.
|
715
|
+
# Items are deliminated with <code>delim</code>, and items are
|
716
|
+
# converted to string in the given block.
|
717
|
+
# If block is omitted, Object#inspect is used.
|
718
|
+
def to_s(delim = "\n")
|
719
|
+
buf = ''
|
720
|
+
init = true
|
721
|
+
self.each_pair do |item, count|
|
722
|
+
if init
|
723
|
+
init = false
|
724
|
+
else
|
725
|
+
buf += delim
|
726
|
+
end
|
727
|
+
item_tmp = block_given? ? yield(item) : item.inspect
|
728
|
+
buf += "\##{count} #{item_tmp}"
|
729
|
+
end
|
730
|
+
buf
|
731
|
+
end
|
732
|
+
|
733
|
+
def inspect # :nodoc:
|
734
|
+
buf = "#<Multiset:"
|
735
|
+
buf += self.to_s(', ')
|
736
|
+
buf += '>'
|
737
|
+
buf
|
738
|
+
end
|
739
|
+
end
|
740
|
+
|
741
|
+
class Hash
|
742
|
+
# <code>self</code>を多重集合に変換し、その結果を返します。
|
743
|
+
# キーを要素、キーに対応する値をその要素の要素数とします。
|
744
|
+
#
|
745
|
+
# (例)<code>{:a => 4, :b => 2}.to_multiset # :aを4個、:bを2個含む多重集合</code>
|
746
|
+
#
|
747
|
+
# Generates multiset from <code>self</code>.
|
748
|
+
# Keys are treated as elements, and values are number of elements
|
749
|
+
# in the multiset. For example,
|
750
|
+
#
|
751
|
+
# <code>{:a => 4, :b => 2}.to_multiset # Multiset with four :a's and two :b's</code>
|
752
|
+
def to_multiset
|
753
|
+
ret = Multiset.new
|
754
|
+
self.each_pair{ |item, count| ret.renew_count(item, count) }
|
755
|
+
ret
|
756
|
+
end
|
757
|
+
end
|