source: EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-array-ext/mrblib/array.rb@ 331

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

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

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