Forum: Ruby Fixnum#to_a

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.
Levin A. (Guest)
on 2006-02-04 11:00
(Received via mailing list)
Hi,

I'd like to propose Fixnum#to_a:

  class Fixnum
    def to_a(base=10,min_length=0)
      self.to_s(base).rjust(min_length).split(//).map { |c| c.to_i(base)
}
    end
  end

  12345.to_a #=> [1,2,3,4,5]
  42.to_a(2) #=> [1,0,1,0,1,0]
  23.to_a(4,5) #=> [0,0,1,1,3]
  -10.to_a #=> ???

This relies on to_s and therefore does not work with a base > 36.  I
don't know how this should word for negative numbers.

Maybe the default base should be 2 to be consistent with Fixnum#[]

Thoughts?

Viele Grü�e,
Levin
Christian N. (Guest)
on 2006-02-04 15:29
(Received via mailing list)
Levin A. <removed_email_address@domain.invalid> writes:

>   12345.to_a #=> [1,2,3,4,5]
>   42.to_a(2) #=> [1,0,1,0,1,0]
>   23.to_a(4,5) #=> [0,0,1,1,3]
>   -10.to_a #=> ???
>
> This relies on to_s and therefore does not work with a base > 36.  I
> don't know how this should word for negative numbers.

It should be twos-complement for negative numbers, of course. ;-)

> Maybe the default base should be 2 to be consistent with Fixnum#[]
>
> Thoughts?

IMO a useful method, *but*: Don't call it #to_a.  to_a has certain
duck-typing aspects, and this usage is too rare to be triggered a lot
(just think of a = 42; b = [*a]).

Also, you may want to extend it to be like APL's "encode" (tack), so you
can do stuff like:

1776.encode(8)                 # => [1, 0, 2, 2]  (octal)
105246.encode(0, 1760, 3, 12)  # => [1,     1163,  1,    6]
                               #    [miles, yards, feet, inches]

Then, we'd also need an "decode":

  [14,   12,    20,      51].decode(0, 24, 60, 60)  # => 1254057
# [days, hours, minutes, seconds]

(The examples were taken from "APL\360 Primer, Student Text, IBM,
1969".)
Levin A. (Guest)
on 2006-02-04 16:45
(Received via mailing list)
On 2/4/06, Christian N. <removed_email_address@domain.invalid> wrote:
> Levin A. <removed_email_address@domain.invalid> writes:
>
> >   12345.to_a #=> [1,2,3,4,5]
> >   42.to_a(2) #=> [1,0,1,0,1,0]
> >   23.to_a(4,5) #=> [0,0,1,1,3]
> >   -10.to_a #=> ???

The order should probably be reversed, so that the least significant
digit is at index 0:

  12345.encode(10) #=> [5,4,3,2,1]

> It should be twos-complement for negative numbers, of course. ;-)

But this would need to create an infinite array:

  -2.encode(2) #=> [0,1,1,1,1,1,1,1,1,1,...]

> > Maybe the default base should be 2 to be consistent with Fixnum#[]
> >
> > Thoughts?
>
> IMO a useful method, *but*: Don't call it #to_a.  to_a has certain
> duck-typing aspects, and this usage is too rare to be triggered a lot
> (just think of a = 42; b = [*a]).

Good point.

> Also, you may want to extend it to be like APL's "encode" (tack), so you
> can do stuff like:
>
> 1776.encode(8)                 # => [1, 0, 2, 2]  (octal)
> 105246.encode(0, 1760, 3, 12)  # => [1,     1163,  1,    6]
>                                #    [miles, yards, feet, inches]

This is probably more useful than the min_length parameter.

> Then, we'd also need an "decode":
>
>   [14,   12,    20,      51].decode(0, 24, 60, 60)  # => 1254057
> # [days, hours, minutes, seconds]
>
> (The examples were taken from "APL\360 Primer, Student Text, IBM, 1969".)

Viele Grü�e,
Levin
Christian N. (Guest)
on 2006-02-04 17:18
(Received via mailing list)
Christian N. <removed_email_address@domain.invalid> writes:

> Also, you may want to extend it to be like APL's "encode" (tack), so you
> can do stuff like:

For fun, an implementation of encode/decode.


class Integer
  def encode(restbase, *bases)
    mybases = bases.dup
    result = []
    n = self

    while base = mybases.pop || restbase
      break  if n < base
      break  if base.zero?
      result << n % base
      n = n / base
    end

    result << n

    if (missing = bases.size - result.size + 1) > 0
      result.concat [0] * missing
    end

    result.reverse!
  end
end

class Array
  def decode(restbase, *bases)
    bases = bases.dup
    result = 0
    factor = 1

    self.reverse_each { |a|
      base = bases.pop || restbase
      result += a * factor
      factor *= base
    }

    result
  end
end

p 01776.encode(8)                # => [1, 0, 2, 2]  (octal -> decimal)
p [1, 7, 7, 6].decode(8)         # => 1022

p 105246.encode(0, 1760, 3, 12)  # => [1,     1163,  1,    6]
                                 #    [miles, yards, feet, inches]

p [14,   12,    20,      57].decode(0, 24, 60, 60)  # => 1254057
# [days, hours, minutes, seconds]

duration = 324477
p "Runtime: %d days %02d:%02d:%02d" % duration.encode(0, 24, 60, 60)


Happy hacking,
Harold H. (Guest)
on 2006-02-04 20:37
(Received via mailing list)
Happy hacking indeed!

Your code made playing with this problem a lot more fun:
http://mathschallenge.net/index.php?section=projec...

Regards,
-Harold
Levin A. (Guest)
on 2006-02-04 20:43
(Received via mailing list)
On 2/4/06, Christian N. <removed_email_address@domain.invalid> wrote:
> Christian N. <removed_email_address@domain.invalid> writes:
>
> > Also, you may want to extend it to be like APL's "encode" (tack), so you
> > can do stuff like:
>
> For fun, an implementation of encode/decode.

I played with your code a bit more, reversed the order of the created
array and added some test cases.  What I have now is attached.

IMHO, something like that would be nice to have in the standard library.

Grü�e,
Levin
This topic is locked and can not be replied to.