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.
Af95bdaf87958c40150b813e94381bfd?d=identicon&s=25 Christer Nilsson (christer)
on 2005-12-13 15: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
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2005-12-13 16:44
(Received via mailing list)
Hi --

On Tue, 13 Dec 2005, Christer Nilsson 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
dblack@wobblini.net

"Ruby for Rails", forthcoming from Manning Publications, April 2006!
F91f1034d620825594db83db92ca1711?d=identicon&s=25 Michael Ulm (Guest)
on 2005-12-13 16:47
(Received via mailing list)
Christer Nilsson 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
Af95bdaf87958c40150b813e94381bfd?d=identicon&s=25 Christer Nilsson (christer)
on 2005-12-13 17: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
Af95bdaf87958c40150b813e94381bfd?d=identicon&s=25 Christer Nilsson (christer)
on 2005-12-13 17: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.