 
 This page contains automated test results for code from O'Reilly's Ruby Cookbook. If this code looks interesting or useful, you might want to buy the whole book.
| Making Sure a Sorted Array Stays Sorted | ||
|---|---|---|
| Code | Expected | Actual | 
| class SortedArray < Array
  def initialize(*args, &sort_by)
    @sort_by = sort_by || Proc.new { |x,y| x <=> y }	
    super(*args)
    sort! &sort_by
  end
  def insert(i, v)
    # The next line could be further optimized to perform a
    # binary search.
    insert_before = index(find { |x| @sort_by.call(x, v) == 1 })
    super(insert_before ? insert_before : -1, v)
  end
  def <<(v)
    insert(0, v)
  end
  alias push <<
  alias unshift <<
  ["collect!", "flatten!", "[]="].each do |method_name|
    module_eval %{
      def #{method_name}(*args)
        super
        sort! &@sort_by
      end
    }
  end
  def reverse!
    #Do nothing; reversing the array would disorder it.
  end
end
a = SortedArray.new([3,2,1]) | [1, 2, 3] | [1, 2, 3] | 
| unsorted= ["b", "aa", "a", "cccc", "1", "zzzzz", "k", "z"] strings_by_alpha = SortedArray.new(unsorted) | ["1", "a", "aa", "b", "cccc", "k", "z", "zzzzz"] | ["1", "a", "aa", "b", "cccc", "k", "z", "zzzzz"] | 
| strings_by_length = SortedArray.new(unsorted) do |x,y| x.length <=> y.length end | ["b", "z", "a", "k", "1", "aa", "cccc", "zzzzz"] | ["b", "z", "a", "k", "1", "aa", "cccc", "zzzzz"] | 
| a << -1 | [-1, 1, 2, 3] | [-1, 1, 2, 3] | 
| a << 1.5 | [-1, 1, 1.5, 2, 3] | [-1, 1, 1.5, 2, 3] | 
| a.push(2.5) | [-1, 1, 1.5, 2, 2.5, 3] | [-1, 1, 1.5, 2, 2.5, 3] | 
| a.unshift(1.6) | [-1, 1, 1.5, 1.6, 2, 2.5, 3] | [-1, 1, 1.5, 1.6, 2, 2.5, 3] | 
| a = SortedArray.new([10, 6, 4, -4, 200, 100]) | [-4, 4, 6, 10, 100, 200] | [-4, 4, 6, 10, 100, 200] | 
| a.collect! { |x| x * -1 } | [-200, -100, -10, -6, -4, 4] | [-200, -100, -10, -6, -4, 4] | 
| a[3] = 25 a | [-200, -100, -10, -4, 4, 25] | [-200, -100, -10, -4, 4, 25] | 
| a[1..2] = [6000, 10, 600, 6] a | [-200, -4, 4, 6, 10, 25, 600, 6000] | [-200, -4, 4, 6, 10, 25, 600, 6000] | 
| class SortedArray
  def []=(*args)    
    if args.size == 3     
      #e.g. "a[6,3] = [1,2,3]"
      start, length, value = args
      slice! Range.new(start, start+length, true)
      (value.respond_to? :each) ? value.each { |x| self << x } : self << value
    elsif args.size == 2
      index, value = args  
      if index.is_a? Numeric
        #e.g. "a[0] = 10" (the most common form of array assignment)
        delete_at(index)
        self << value
      elsif index.is_a? Range
        #e.g. "a[0..3] = [1,2,3]"
        slice! index
        (value.respond_to? :each) ? value.each { |x| self << x } : self << value
      else
        #Not supported. Delegate to superclass; will probably give an error.
        super
        sort!(&sort_by)
      end
    else
      #Not supported. Delegate to superclass; will probably give an error.
      super
      sort!(&sort_by)
    end
  end
end
a = SortedArray.new([1,2,3,4,5,6])
a[0] = 10
a | [2, 3, 4, 5, 6, 10] | [2, 3, 4, 5, 6, 10] | 
| a[0, 2] = [100, 200] a | [4, 5, 6, 10, 100, 200] | [4, 5, 6, 10, 100, 200] | 
| a[1..2] = [-4, 6] a | [-4, 4, 6, 10, 100, 200] | [-4, 4, 6, 10, 100, 200] | 
| stripes = SortedArray.new(["aardwolf", "zebrafish"]) stripes[1].upcase! stripes | ["aardwolf", "ZEBRAFISH"] | ["aardwolf", "ZEBRAFISH"] | 
| stripes.sort! | ["ZEBRAFISH", "aardwolf"] | ["ZEBRAFISH", "aardwolf"] | 
| class Object
  def to_frozen
    f = self
    unless frozen?       
      begin
        f = dup.freeze
      rescue TypeError 
        #This object can't be duped (e.g. Fixnum); fortunately,
        #it usually can't be modified either
      end
    end
    return f
  end
end
class FrozenCopySortedArray < SortedArray
  def insert(i, v)    
    insert_before = index(find { |x| x > v })
    super(insert_before ? insert_before : -1, v.to_frozen)
  end
  ["initialize", "collect!", "flatten!"].each do |method_name|
    define_method(method_name) do
      super
      each_with_index { |x, i| self[i] = x.to_frozen }
      # No need to sort; by doing an assignment to every element
      # in the array, we've made #insert keep the array sorted.
    end
  end
end
stripes = SortedArray.new(["aardwolf", "zebrafish"])
stripes[1].upcase! | TypeError: can't modify frozen string | |
| [1, "string"].sort | ArgumentError: comparison of Fixnum with String failed ... | ArgumentError: comparison of Fixnum with String failed from (irb):116:in `sort' from (irb):116 from :0 | 
| a = SortedArray.new([1]) a << "string" | ArgumentError: comparison of Fixnum with String failed | |
| a = SortedArray.new([3, 2, 1]) | [1, 2, 3] | [1, 2, 3] | 
| a += [1, -10] | [1, 2, 3, 1, -10] | [1, 2, 3, 1, -10] | 
| a.class | Array | Array | 
| class SortedArray
  def + (other_array)
    SortedArray.new(super)
  end
end | nil | |