Forum: Ruby Array.invert

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Christer N. (Guest)
on 2005-12-13 16:43
I would like to see invert "rubyfied".
(Yes, I'm trying to get a grip of what this word means :-)

class Array
  def invert
    res=[]
    for i in 0...self.size
      if self[i] != nil then
        for b in self[i]
          res[b] = [] if res[b].nil?
          res[b] << i
        end
      end
    end
    res
  end
end

require 'test/unit'
class TestArray < Test::Unit::TestCase
  def test_invert_1
    a = [[1,3],[1,4,5]]
    b = [nil,[0,1],nil,[0],[1],[1]]
    assert_equal b,a.invert
    assert_equal a,b.invert
  end

  def test_invert_2
    a = []
    a << [3,9,13]         # 0
    a << [3,11,14]        # 1
    a << [3,14,15]        # 2
    a << [4,1,4]          # 3
    a << [4,8,9]          # 4
    a << [5,0,1]          # 5
    a << [6,6,7]          # 6
    a << [14,2,6]         # 7
    a << [10,5,8,12,15]   # 8
    a << [10,10,11,12,13] # 9
    a << [11,0,3,7,10]    # 10
    a << [17,2,3,4,5]     # 11

    # behead...
    c = a.map {|head, *tail| tail}

    b = []
    b << [5,10] # 0
    b << [3,5]  # 1
    b << [7,11] # 2
    b << [10,11]# 3
    b << [3,11] # 4
    b << [8,11] # 5
    b << [6,7]  # 6
    b << [6,10] # 7
    b << [4,8]  # 8
    b << [0,4]  # 9
    b << [9,10] # 10
    b << [1,9]  # 11
    b << [8,9]  # 12
    b << [0,9]  # 13
    b << [1,2]  # 14
    b << [2,8]  # 15

    assert_equal b,c.invert
    assert_equal c,b.invert

  end
end

Christer
unknown (Guest)
on 2005-12-13 17:44
(Received via mailing list)
Hi --

On Tue, 13 Dec 2005, Christer N. wrote:

> I would like to see invert "rubyfied".
> (Yes, I'm trying to get a grip of what this word means :-)

Aren't we all?  But the trying is so much fun :-)

Here's a version that might be more idiomatic, and that passes all
your tests:

class Array
   def invert
     res=[]
     each_with_index do |e,i|
       if e
         e.each do |f|
           (res[f] ||= []) << i
         end
       end
     end
     res
   end
end


David

--
David A. Black
removed_email_address@domain.invalid

"Ruby for Rails", forthcoming from Manning Publications, April 2006!
Michael U. (Guest)
on 2005-12-13 17:47
(Received via mailing list)
Christer N. wrote:

>           res[b] << i
>         end
>       end
>     end
>     res
>   end
> end
>

I suggest

class Array
   def invert
     result = []
     each_with_index do |ary, idx|
       next if ary.nil?
       ary.each {|val| (result[val] ||= []).push(idx)}
     end
     result
   end
end

As a matter of taste, you may want to write the two middle
lines in just one line as

       ary.each {|val| (result[val] ||= []).push(idx)} unless ary.nil?

HTH,

Michael
Christer N. (Guest)
on 2005-12-13 18:11
Beautiful, thank you David and Michael.
Must be hard to improve now!

[David, Michael].merge :

class Array
   def invert
     res = []
     each_with_index do |e, i|
       e.each {|f| (res[f] ||= []) << i} if e
     end
     res
   end
end

Christer
Christer N. (Guest)
on 2005-12-13 18:22
Hash.invert exists, returning another Hash.

Is there any other interesting interpretation of Array.invert ?

(Matrix.invert is another thing :-)

Is Array.invert useful enough to be a part of the original set of
methods of Array?

I see two reasons for building in methods,
  the first one is to make programmer code faster,
  the second is to make code execute faster.

If Array.invert is seldom used and possible to execute fast, already in
Ruby, there is no good reason to build it in.

Personally, I used Array.invert in finding solutions for kakuro.

Christer
This topic is locked and can not be replied to.