source: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-array-ext/mrblib/array.rb@ 439

Last change on this file since 439 was 439, checked in by coas-nagasima, 4 years ago

mrubyを2.1.1に更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-ruby;charset=UTF-8
File size: 24.9 KB
Line 
1class Array
2 ##
3 # call-seq:
4 # ary.uniq! -> ary or nil
5 # ary.uniq! { |item| ... } -> ary or nil
6 #
7 # Removes duplicate elements from +self+.
8 # Returns <code>nil</code> if no changes are made (that is, no
9 # duplicates are found).
10 #
11 # a = [ "a", "a", "b", "b", "c" ]
12 # a.uniq! #=> ["a", "b", "c"]
13 # b = [ "a", "b", "c" ]
14 # b.uniq! #=> nil
15 # c = [["student","sam"], ["student","george"], ["teacher","matz"]]
16 # c.uniq! { |s| s.first } # => [["student", "sam"], ["teacher", "matz"]]
17 #
18 def uniq!(&block)
19 hash = {}
20 if block
21 self.each do |val|
22 key = block.call(val)
23 hash[key] = val unless hash.key?(key)
24 end
25 result = hash.values
26 else
27 hash = {}
28 self.each do |val|
29 hash[val] = val
30 end
31 result = hash.keys
32 end
33 if result.size == self.size
34 nil
35 else
36 self.replace(result)
37 end
38 end
39
40 ##
41 # call-seq:
42 # ary.uniq -> new_ary
43 # ary.uniq { |item| ... } -> new_ary
44 #
45 # Returns a new array by removing duplicate values in +self+.
46 #
47 # a = [ "a", "a", "b", "b", "c" ]
48 # a.uniq #=> ["a", "b", "c"]
49 #
50 # b = [["student","sam"], ["student","george"], ["teacher","matz"]]
51 # b.uniq { |s| s.first } # => [["student", "sam"], ["teacher", "matz"]]
52 #
53 def uniq(&block)
54 ary = self.dup
55 ary.uniq!(&block)
56 ary
57 end
58
59 ##
60 # call-seq:
61 # ary - other_ary -> new_ary
62 #
63 # Array Difference---Returns a new array that is a copy of
64 # the original array, removing any items that also appear in
65 # <i>other_ary</i>. (If you need set-like behavior, see the
66 # library class Set.)
67 #
68 # [ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ] #=> [ 3, 3, 5 ]
69 #
70 def -(elem)
71 raise TypeError, "can't convert #{elem.class} into Array" unless elem.class == Array
72
73 hash = {}
74 array = []
75 idx = 0
76 len = elem.size
77 while idx < len
78 hash[elem[idx]] = true
79 idx += 1
80 end
81 idx = 0
82 len = size
83 while idx < len
84 v = self[idx]
85 array << v unless hash[v]
86 idx += 1
87 end
88 array
89 end
90
91 ##
92 # call-seq:
93 # ary.difference(other_ary1, other_ary2, ...) -> new_ary
94 #
95 # Returns a new array that is a copy of the original array, removing all
96 # occurrences of any item that also appear in +other_ary+. The order is
97 # preserved from the original array.
98 #
99 def difference(*args)
100 ary = self
101 args.each do |x|
102 ary = ary - x
103 end
104 ary
105 end
106
107 ##
108 # call-seq:
109 # ary | other_ary -> new_ary
110 #
111 # Set Union---Returns a new array by joining this array with
112 # <i>other_ary</i>, removing duplicates.
113 #
114 # [ "a", "b", "c" ] | [ "c", "d", "a" ]
115 # #=> [ "a", "b", "c", "d" ]
116 #
117 def |(elem)
118 raise TypeError, "can't convert #{elem.class} into Array" unless elem.class == Array
119
120 ary = self + elem
121 ary.uniq! or ary
122 end
123
124 ##
125 # call-seq:
126 # ary.union(other_ary,...) -> new_ary
127 #
128 # Set Union---Returns a new array by joining this array with
129 # <i>other_ary</i>, removing duplicates.
130 #
131 # ["a", "b", "c"].union(["c", "d", "a"], ["a", "c", "e"])
132 # #=> ["a", "b", "c", "d", "e"]
133 #
134 def union(*args)
135 ary = self.dup
136 args.each do |x|
137 ary.concat(x)
138 ary.uniq!
139 end
140 ary
141 end
142
143 ##
144 # call-seq:
145 # ary & other_ary -> new_ary
146 #
147 # Set Intersection---Returns a new array
148 # containing elements common to the two arrays, with no duplicates.
149 #
150 # [ 1, 1, 3, 5 ] & [ 1, 2, 3 ] #=> [ 1, 3 ]
151 #
152 def &(elem)
153 raise TypeError, "can't convert #{elem.class} into Array" unless elem.class == Array
154
155 hash = {}
156 array = []
157 idx = 0
158 len = elem.size
159 while idx < len
160 hash[elem[idx]] = true
161 idx += 1
162 end
163 idx = 0
164 len = size
165 while idx < len
166 v = self[idx]
167 if hash[v]
168 array << v
169 hash.delete v
170 end
171 idx += 1
172 end
173 array
174 end
175
176 ##
177 # call-seq:
178 # ary.intersection(other_ary,...) -> new_ary
179 #
180 # Set Intersection---Returns a new array containing elements common to
181 # this array and <i>other_ary</i>s, removing duplicates. The order is
182 # preserved from the original array.
183 #
184 # [1, 2, 3].intersection([3, 4, 1], [1, 3, 5]) #=> [1, 3]
185 #
186 def intersection(*args)
187 ary = self
188 args.each do |x|
189 ary = ary & x
190 end
191 ary
192 end
193
194 ##
195 # call-seq:
196 # ary.flatten -> new_ary
197 # ary.flatten(level) -> new_ary
198 #
199 # Returns a new array that is a one-dimensional flattening of this
200 # array (recursively). That is, for every element that is an array,
201 # extract its elements into the new array. If the optional
202 # <i>level</i> argument determines the level of recursion to flatten.
203 #
204 # s = [ 1, 2, 3 ] #=> [1, 2, 3]
205 # t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]]
206 # a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10]
207 # a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
208 # a = [ 1, 2, [3, [4, 5] ] ]
209 # a.flatten(1) #=> [1, 2, 3, [4, 5]]
210 #
211 def flatten(depth=nil)
212 res = dup
213 res.flatten! depth
214 res
215 end
216
217 ##
218 # call-seq:
219 # ary.flatten! -> ary or nil
220 # ary.flatten!(level) -> array or nil
221 #
222 # Flattens +self+ in place.
223 # Returns <code>nil</code> if no modifications were made (i.e.,
224 # <i>ary</i> contains no subarrays.) If the optional <i>level</i>
225 # argument determines the level of recursion to flatten.
226 #
227 # a = [ 1, 2, [3, [4, 5] ] ]
228 # a.flatten! #=> [1, 2, 3, 4, 5]
229 # a.flatten! #=> nil
230 # a #=> [1, 2, 3, 4, 5]
231 # a = [ 1, 2, [3, [4, 5] ] ]
232 # a.flatten!(1) #=> [1, 2, 3, [4, 5]]
233 #
234 def flatten!(depth=nil)
235 modified = false
236 ar = []
237 idx = 0
238 len = size
239 while idx < len
240 e = self[idx]
241 if e.is_a?(Array) && (depth.nil? || depth > 0)
242 ar += e.flatten(depth.nil? ? nil : depth - 1)
243 modified = true
244 else
245 ar << e
246 end
247 idx += 1
248 end
249 if modified
250 self.replace(ar)
251 else
252 nil
253 end
254 end
255
256 ##
257 # call-seq:
258 # ary.compact -> new_ary
259 #
260 # Returns a copy of +self+ with all +nil+ elements removed.
261 #
262 # [ "a", nil, "b", nil, "c", nil ].compact
263 # #=> [ "a", "b", "c" ]
264 #
265 def compact
266 result = self.dup
267 result.compact!
268 result
269 end
270
271 ##
272 # call-seq:
273 # ary.compact! -> ary or nil
274 #
275 # Removes +nil+ elements from the array.
276 # Returns +nil+ if no changes were made, otherwise returns
277 # <i>ary</i>.
278 #
279 # [ "a", nil, "b", nil, "c" ].compact! #=> [ "a", "b", "c" ]
280 # [ "a", "b", "c" ].compact! #=> nil
281 #
282 def compact!
283 result = self.select { |e| !e.nil? }
284 if result.size == self.size
285 nil
286 else
287 self.replace(result)
288 end
289 end
290
291 # for efficiency
292 def reverse_each(&block)
293 return to_enum :reverse_each unless block
294
295 i = self.size - 1
296 while i>=0
297 block.call(self[i])
298 i -= 1
299 end
300 self
301 end
302
303 ##
304 # call-seq:
305 # ary.fetch(index) -> obj
306 # ary.fetch(index, default) -> obj
307 # ary.fetch(index) { |index| block } -> obj
308 #
309 # Tries to return the element at position +index+, but throws an IndexError
310 # exception if the referenced +index+ lies outside of the array bounds. This
311 # error can be prevented by supplying a second argument, which will act as a
312 # +default+ value.
313 #
314 # Alternatively, if a block is given it will only be executed when an
315 # invalid +index+ is referenced.
316 #
317 # Negative values of +index+ count from the end of the array.
318 #
319 # a = [ 11, 22, 33, 44 ]
320 # a.fetch(1) #=> 22
321 # a.fetch(-1) #=> 44
322 # a.fetch(4, 'cat') #=> "cat"
323 # a.fetch(100) { |i| puts "#{i} is out of bounds" }
324 # #=> "100 is out of bounds"
325 #
326
327 def fetch(n, ifnone=NONE, &block)
328 warn "block supersedes default value argument" if !n.nil? && ifnone != NONE && block
329
330 idx = n
331 if idx < 0
332 idx += size
333 end
334 if idx < 0 || size <= idx
335 return block.call(n) if block
336 if ifnone == NONE
337 raise IndexError, "index #{n} outside of array bounds: #{-size}...#{size}"
338 end
339 return ifnone
340 end
341 self[idx]
342 end
343
344 ##
345 # call-seq:
346 # ary.fill(obj) -> ary
347 # ary.fill(obj, start [, length]) -> ary
348 # ary.fill(obj, range ) -> ary
349 # ary.fill { |index| block } -> ary
350 # ary.fill(start [, length] ) { |index| block } -> ary
351 # ary.fill(range) { |index| block } -> ary
352 #
353 # The first three forms set the selected elements of +self+ (which
354 # may be the entire array) to +obj+.
355 #
356 # A +start+ of +nil+ is equivalent to zero.
357 #
358 # A +length+ of +nil+ is equivalent to the length of the array.
359 #
360 # The last three forms fill the array with the value of the given block,
361 # which is passed the absolute index of each element to be filled.
362 #
363 # Negative values of +start+ count from the end of the array, where +-1+ is
364 # the last element.
365 #
366 # a = [ "a", "b", "c", "d" ]
367 # a.fill("x") #=> ["x", "x", "x", "x"]
368 # a.fill("w", -1) #=> ["x", "x", "x", "w"]
369 # a.fill("z", 2, 2) #=> ["x", "x", "z", "z"]
370 # a.fill("y", 0..1) #=> ["y", "y", "z", "z"]
371 # a.fill { |i| i*i } #=> [0, 1, 4, 9]
372 # a.fill(-2) { |i| i*i*i } #=> [0, 1, 8, 27]
373 # a.fill(1, 2) { |i| i+1 } #=> [0, 2, 3, 27]
374 # a.fill(0..1) { |i| i+1 } #=> [1, 2, 3, 27]
375 #
376
377 def fill(arg0=nil, arg1=nil, arg2=nil, &block)
378 if arg0.nil? && arg1.nil? && arg2.nil? && !block
379 raise ArgumentError, "wrong number of arguments (0 for 1..3)"
380 end
381
382 beg = len = 0
383 ary = []
384 if block
385 if arg0.nil? && arg1.nil? && arg2.nil?
386 # ary.fill { |index| block } -> ary
387 beg = 0
388 len = self.size
389 elsif !arg0.nil? && arg0.kind_of?(Range)
390 # ary.fill(range) { |index| block } -> ary
391 beg = arg0.begin
392 beg += self.size if beg < 0
393 len = arg0.end
394 len += self.size if len < 0
395 len += 1 unless arg0.exclude_end?
396 elsif !arg0.nil?
397 # ary.fill(start [, length] ) { |index| block } -> ary
398 beg = arg0
399 beg += self.size if beg < 0
400 if arg1.nil?
401 len = self.size
402 else
403 len = arg0 + arg1
404 end
405 end
406 else
407 if !arg0.nil? && arg1.nil? && arg2.nil?
408 # ary.fill(obj) -> ary
409 beg = 0
410 len = self.size
411 elsif !arg0.nil? && !arg1.nil? && arg1.kind_of?(Range)
412 # ary.fill(obj, range ) -> ary
413 beg = arg1.begin
414 beg += self.size if beg < 0
415 len = arg1.end
416 len += self.size if len < 0
417 len += 1 unless arg1.exclude_end?
418 elsif !arg0.nil? && !arg1.nil?
419 # ary.fill(obj, start [, length]) -> ary
420 beg = arg1
421 beg += self.size if beg < 0
422 if arg2.nil?
423 len = self.size
424 else
425 len = beg + arg2
426 end
427 end
428 end
429
430 i = beg
431 if block
432 while i < len
433 self[i] = block.call(i)
434 i += 1
435 end
436 else
437 while i < len
438 self[i] = arg0
439 i += 1
440 end
441 end
442 self
443 end
444
445 ##
446 # call-seq:
447 # ary.rotate(count=1) -> new_ary
448 #
449 # Returns a new array by rotating +self+ so that the element at +count+ is
450 # the first element of the new array.
451 #
452 # If +count+ is negative then it rotates in the opposite direction, starting
453 # from the end of +self+ where +-1+ is the last element.
454 #
455 # a = [ "a", "b", "c", "d" ]
456 # a.rotate #=> ["b", "c", "d", "a"]
457 # a #=> ["a", "b", "c", "d"]
458 # a.rotate(2) #=> ["c", "d", "a", "b"]
459 # a.rotate(-3) #=> ["b", "c", "d", "a"]
460
461 def rotate(count=1)
462 ary = []
463 len = self.length
464
465 if len > 0
466 idx = (count < 0) ? (len - (~count % len) - 1) : (count % len) # rotate count
467 len.times do
468 ary << self[idx]
469 idx += 1
470 idx = 0 if idx > len-1
471 end
472 end
473 ary
474 end
475
476 ##
477 # call-seq:
478 # ary.rotate!(count=1) -> ary
479 #
480 # Rotates +self+ in place so that the element at +count+ comes first, and
481 # returns +self+.
482 #
483 # If +count+ is negative then it rotates in the opposite direction, starting
484 # from the end of the array where +-1+ is the last element.
485 #
486 # a = [ "a", "b", "c", "d" ]
487 # a.rotate! #=> ["b", "c", "d", "a"]
488 # a #=> ["b", "c", "d", "a"]
489 # a.rotate!(2) #=> ["d", "a", "b", "c"]
490 # a.rotate!(-3) #=> ["a", "b", "c", "d"]
491
492 def rotate!(count=1)
493 self.replace(self.rotate(count))
494 end
495
496 ##
497 # call-seq:
498 # ary.delete_if { |item| block } -> ary
499 # ary.delete_if -> Enumerator
500 #
501 # Deletes every element of +self+ for which block evaluates to +true+.
502 #
503 # The array is changed instantly every time the block is called, not after
504 # the iteration is over.
505 #
506 # See also Array#reject!
507 #
508 # If no block is given, an Enumerator is returned instead.
509 #
510 # scores = [ 97, 42, 75 ]
511 # scores.delete_if {|score| score < 80 } #=> [97]
512
513 def delete_if(&block)
514 return to_enum :delete_if unless block
515
516 idx = 0
517 while idx < self.size do
518 if block.call(self[idx])
519 self.delete_at(idx)
520 else
521 idx += 1
522 end
523 end
524 self
525 end
526
527 ##
528 # call-seq:
529 # ary.reject! { |item| block } -> ary or nil
530 # ary.reject! -> Enumerator
531 #
532 # Equivalent to Array#delete_if, deleting elements from +self+ for which the
533 # block evaluates to +true+, but returns +nil+ if no changes were made.
534 #
535 # The array is changed instantly every time the block is called, not after
536 # the iteration is over.
537 #
538 # See also Enumerable#reject and Array#delete_if.
539 #
540 # If no block is given, an Enumerator is returned instead.
541
542 def reject!(&block)
543 return to_enum :reject! unless block
544
545 len = self.size
546 idx = 0
547 while idx < self.size do
548 if block.call(self[idx])
549 self.delete_at(idx)
550 else
551 idx += 1
552 end
553 end
554 if self.size == len
555 nil
556 else
557 self
558 end
559 end
560
561 ##
562 # call-seq:
563 # ary.insert(index, obj...) -> ary
564 #
565 # Inserts the given values before the element with the given +index+.
566 #
567 # Negative indices count backwards from the end of the array, where +-1+ is
568 # the last element.
569 #
570 # a = %w{ a b c d }
571 # a.insert(2, 99) #=> ["a", "b", 99, "c", "d"]
572 # a.insert(-2, 1, 2, 3) #=> ["a", "b", 99, "c", 1, 2, 3, "d"]
573
574 def insert(idx, *args)
575 idx += self.size + 1 if idx < 0
576 self[idx, 0] = args
577 self
578 end
579
580 ##
581 # call-seq:
582 # ary.bsearch {|x| block } -> elem
583 #
584 # By using binary search, finds a value from this array which meets
585 # the given condition in O(log n) where n is the size of the array.
586 #
587 # You can use this method in two use cases: a find-minimum mode and
588 # a find-any mode. In either case, the elements of the array must be
589 # monotone (or sorted) with respect to the block.
590 #
591 # In find-minimum mode (this is a good choice for typical use case),
592 # the block must return true or false, and there must be an index i
593 # (0 <= i <= ary.size) so that:
594 #
595 # - the block returns false for any element whose index is less than
596 # i, and
597 # - the block returns true for any element whose index is greater
598 # than or equal to i.
599 #
600 # This method returns the i-th element. If i is equal to ary.size,
601 # it returns nil.
602 #
603 # ary = [0, 4, 7, 10, 12]
604 # ary.bsearch {|x| x >= 4 } #=> 4
605 # ary.bsearch {|x| x >= 6 } #=> 7
606 # ary.bsearch {|x| x >= -1 } #=> 0
607 # ary.bsearch {|x| x >= 100 } #=> nil
608 #
609 # In find-any mode (this behaves like libc's bsearch(3)), the block
610 # must return a number, and there must be two indices i and j
611 # (0 <= i <= j <= ary.size) so that:
612 #
613 # - the block returns a positive number for ary[k] if 0 <= k < i,
614 # - the block returns zero for ary[k] if i <= k < j, and
615 # - the block returns a negative number for ary[k] if
616 # j <= k < ary.size.
617 #
618 # Under this condition, this method returns any element whose index
619 # is within i...j. If i is equal to j (i.e., there is no element
620 # that satisfies the block), this method returns nil.
621 #
622 # ary = [0, 4, 7, 10, 12]
623 # # try to find v such that 4 <= v < 8
624 # ary.bsearch {|x| 1 - (x / 4).truncate } #=> 4 or 7
625 # # try to find v such that 8 <= v < 10
626 # ary.bsearch {|x| 4 - (x / 2).truncate } #=> nil
627 #
628 # You must not mix the two modes at a time; the block must always
629 # return either true/false, or always return a number. It is
630 # undefined which value is actually picked up at each iteration.
631
632 def bsearch(&block)
633 return to_enum :bsearch unless block
634
635 if idx = bsearch_index(&block)
636 self[idx]
637 else
638 nil
639 end
640 end
641
642 ##
643 # call-seq:
644 # ary.bsearch_index {|x| block } -> int or nil
645 #
646 # By using binary search, finds an index of a value from this array which
647 # meets the given condition in O(log n) where n is the size of the array.
648 #
649 # It supports two modes, depending on the nature of the block and they are
650 # exactly the same as in the case of #bsearch method with the only difference
651 # being that this method returns the index of the element instead of the
652 # element itself. For more details consult the documentation for #bsearch.
653
654 def bsearch_index(&block)
655 return to_enum :bsearch_index unless block
656
657 low = 0
658 high = size
659 satisfied = false
660
661 while low < high
662 mid = ((low+high)/2).truncate
663 res = block.call self[mid]
664
665 case res
666 when 0 # find-any mode: Found!
667 return mid
668 when Numeric # find-any mode: Continue...
669 in_lower_half = res < 0
670 when true # find-min mode
671 in_lower_half = true
672 satisfied = true
673 when false, nil # find-min mode
674 in_lower_half = false
675 else
676 raise TypeError, 'invalid block result (must be numeric, true, false or nil)'
677 end
678
679 if in_lower_half
680 high = mid
681 else
682 low = mid + 1
683 end
684 end
685
686 satisfied ? low : nil
687 end
688
689 ##
690 # call-seq:
691 # ary.keep_if { |item| block } -> ary
692 # ary.keep_if -> Enumerator
693 #
694 # Deletes every element of +self+ for which the given block evaluates to
695 # +false+.
696 #
697 # See also Array#select!
698 #
699 # If no block is given, an Enumerator is returned instead.
700 #
701 # a = [1, 2, 3, 4, 5]
702 # a.keep_if { |val| val > 3 } #=> [4, 5]
703
704 def keep_if(&block)
705 return to_enum :keep_if unless block
706
707 idx = 0
708 len = self.size
709 while idx < self.size do
710 if block.call(self[idx])
711 idx += 1
712 else
713 self.delete_at(idx)
714 end
715 end
716 self
717 end
718
719 ##
720 # call-seq:
721 # ary.select! {|item| block } -> ary or nil
722 # ary.select! -> Enumerator
723 #
724 # Invokes the given block passing in successive elements from +self+,
725 # deleting elements for which the block returns a +false+ value.
726 #
727 # If changes were made, it will return +self+, otherwise it returns +nil+.
728 #
729 # See also Array#keep_if
730 #
731 # If no block is given, an Enumerator is returned instead.
732
733 def select!(&block)
734 return to_enum :select! unless block
735
736 result = []
737 idx = 0
738 len = size
739 while idx < len
740 elem = self[idx]
741 result << elem if block.call(elem)
742 idx += 1
743 end
744 return nil if len == result.size
745 self.replace(result)
746 end
747
748 ##
749 # call-seq:
750 # ary.index(val) -> int or nil
751 # ary.index {|item| block } -> int or nil
752 #
753 # Returns the _index_ of the first object in +ary+ such that the object is
754 # <code>==</code> to +obj+.
755 #
756 # If a block is given instead of an argument, returns the _index_ of the
757 # first object for which the block returns +true+. Returns +nil+ if no
758 # match is found.
759 #
760 # ISO 15.2.12.5.14
761 def index(val=NONE, &block)
762 return to_enum(:find_index, val) if !block && val == NONE
763
764 if block
765 idx = 0
766 len = size
767 while idx < len
768 return idx if block.call self[idx]
769 idx += 1
770 end
771 else
772 return self.__ary_index(val)
773 end
774 nil
775 end
776
777 ##
778 # call-seq:
779 # ary.dig(idx, ...) -> object
780 #
781 # Extracts the nested value specified by the sequence of <i>idx</i>
782 # objects by calling +dig+ at each step, returning +nil+ if any
783 # intermediate step is +nil+.
784 #
785 def dig(idx,*args)
786 n = self[idx]
787 if args.size > 0
788 n&.dig(*args)
789 else
790 n
791 end
792 end
793
794 ##
795 # call-seq:
796 # ary.permutation { |p| block } -> ary
797 # ary.permutation -> Enumerator
798 # ary.permutation(n) { |p| block } -> ary
799 # ary.permutation(n) -> Enumerator
800 #
801 # When invoked with a block, yield all permutations of length +n+ of the
802 # elements of the array, then return the array itself.
803 #
804 # If +n+ is not specified, yield all permutations of all elements.
805 #
806 # The implementation makes no guarantees about the order in which the
807 # permutations are yielded.
808 #
809 # If no block is given, an Enumerator is returned instead.
810 #
811 # Examples:
812 #
813 # a = [1, 2, 3]
814 # a.permutation.to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
815 # a.permutation(1).to_a #=> [[1],[2],[3]]
816 # a.permutation(2).to_a #=> [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]]
817 # a.permutation(3).to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
818 # a.permutation(0).to_a #=> [[]] # one permutation of length 0
819 # a.permutation(4).to_a #=> [] # no permutations of length 4
820 def permutation(n=self.size, &block)
821 return to_enum(:permutation, n) unless block
822 size = self.size
823 if n == 0
824 yield []
825 elsif 0 < n && n <= size
826 i = 0
827 while i<size
828 result = [self[i]]
829 if n-1 > 0
830 ary = self[0...i] + self[i+1..-1]
831 ary.permutation(n-1) do |c|
832 yield result + c
833 end
834 else
835 yield result
836 end
837 i += 1
838 end
839 end
840 self
841 end
842
843 ##
844 # call-seq:
845 # ary.combination(n) { |c| block } -> ary
846 # ary.combination(n) -> Enumerator
847 #
848 # When invoked with a block, yields all combinations of length +n+ of elements
849 # from the array and then returns the array itself.
850 #
851 # The implementation makes no guarantees about the order in which the
852 # combinations are yielded.
853 #
854 # If no block is given, an Enumerator is returned instead.
855 #
856 # Examples:
857 #
858 # a = [1, 2, 3, 4]
859 # a.combination(1).to_a #=> [[1],[2],[3],[4]]
860 # a.combination(2).to_a #=> [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
861 # a.combination(3).to_a #=> [[1,2,3],[1,2,4],[1,3,4],[2,3,4]]
862 # a.combination(4).to_a #=> [[1,2,3,4]]
863 # a.combination(0).to_a #=> [[]] # one combination of length 0
864 # a.combination(5).to_a #=> [] # no combinations of length 5
865
866 def combination(n, &block)
867 return to_enum(:combination, n) unless block
868 size = self.size
869 if n == 0
870 yield []
871 elsif n == 1
872 i = 0
873 while i<size
874 yield [self[i]]
875 i += 1
876 end
877 elsif n <= size
878 i = 0
879 while i<size
880 result = [self[i]]
881 self[i+1..-1].combination(n-1) do |c|
882 yield result + c
883 end
884 i += 1
885 end
886 end
887 self
888 end
889
890 ##
891 # call-seq:
892 # ary.transpose -> new_ary
893 #
894 # Assumes that self is an array of arrays and transposes the rows and columns.
895 #
896 # If the length of the subarrays don't match, an IndexError is raised.
897 #
898 # Examples:
899 #
900 # a = [[1,2], [3,4], [5,6]]
901 # a.transpose #=> [[1, 3, 5], [2, 4, 6]]
902
903 def transpose
904 return [] if empty?
905
906 column_count = nil
907 self.each do |row|
908 raise TypeError unless row.is_a?(Array)
909 column_count ||= row.size
910 raise IndexError, 'element size differs' unless column_count == row.size
911 end
912
913 Array.new(column_count) do |column_index|
914 self.map { |row| row[column_index] }
915 end
916 end
917
918 ##
919 # call-seq:
920 # ary.to_h -> Hash
921 # ary.to_h{|item| ... } -> Hash
922 #
923 # Returns the result of interpreting <i>aray</i> as an array of
924 # <tt>[key, value]</tt> pairs. If a block is given, it should
925 # return <tt>[key, value]</tt> pairs to construct a hash.
926 #
927 # [[:foo, :bar], [1, 2]].to_h
928 # # => {:foo => :bar, 1 => 2}
929 # [1, 2].to_h{|x| [x, x*2]}
930 # # => {1 => 2, 2 => 4}
931 #
932 def to_h(&blk)
933 h = {}
934 self.each do |v|
935 v = blk.call(v) if blk
936 raise TypeError, "wrong element type #{v.class}" unless Array === v
937 raise ArgumentError, "wrong array length (expected 2, was #{v.length})" unless v.length == 2
938 h[v[0]] = v[1]
939 end
940 h
941 end
942
943 alias append push
944 alias prepend unshift
945 alias filter! select!
946end
Note: See TracBrowser for help on using the repository browser.