Upgrade to 1.46.0
[platform/upstream/nghttp2.git] / third-party / mruby / mrbgems / mruby-array-ext / mrblib / array.rb
1 class 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!
946 end