## Feature #18762

open### Add an Array#undigits that compliments Integer#digits

**Description**

I've found Integer#digits convenient and useful but several times have needed to go from the place-value notation back to an Integer after manipulation and wished there was a complimentary Array#undigits.

```
class Array
def undigits(base = 10)
each_with_index.sum do |digit, exponent|
digit * base**exponent
end
end
end
42.digits.undigits
#=> 42
42.digits(16).undigits(16)
#=> 42
```

Below is my stab at a Ruby implementation with behavior mirroring Integer#digits.

```
class Array
def undigits(base = 10)
base_int = base.to_int
raise TypeError, "wrong argument type #{base_int.class} (expected Integer)" unless base_int.is_a?(Integer)
raise ArgumentError, 'negative radix' if base_int.negative?
raise ArgumentError, "invalid radix #{base_int}" if base_int < 2
each_with_index.sum do |digit, exponent|
raise MathDomainError, 'out of domain' if digit.negative?
digit * base_int**exponent
end
end
end
```

#### Updated by jeremyevans0 (Jeremy Evans) over 2 years ago

**Tracker**changed from*Bug*to*Feature***Backport**deleted ()*2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN*

#### Updated by sawa (Tsuyoshi Sawada) over 2 years ago

Using a chain of two methods `each_with_index`

and `sum`

as well as `**`

for such a simple task is an overkill, and perhaps that is why you feel you want a built-in method. You can simply do:

```
[2, 4].inject{_1 + _2 * 10} # => 42
```

#### Updated by shan (Shannon Skipper) over 2 years ago

sawa (Tsuyoshi Sawada) wrote in #note-3:

Using a chain of two methods

`each_with_index`

and`sum`

as well as`**`

for such a simple task is an overkill, and perhaps that is why you feel you want a built-in method. You can simply do:`[2, 4].inject(0){_1 + _2 * 10} # => 42`

@sawa (Tsuyoshi Sawada) The code you showed would sum the numbers multiplied by 10, resulting in `60`

rather than `42`

.

```
[2, 4].inject(0){_1 + _2 * 10} #=> 60
```

#### Updated by sawa (Tsuyoshi Sawada) over 2 years ago

@shan (Shannon Skipper) (Shannon Skipper)

Sorry. I had the code wrong. A similar code works for an array in backwards.

```
[].inject(0){_1 * 10 + _2} # => 0
[2, 1].inject(0){_1 * 10 + _2} # => 21
[3, 2, 1].inject(0){_1 * 10 + _2} # => 321
[6, 3, 2, 1].inject(0){_1 * 10 + _2} # => 6321
```

#### Updated by shan (Shannon Skipper) over 2 years ago

sawa (Tsuyoshi Sawada) wrote in #note-5:

@shan (Shannon Skipper) (Shannon Skipper)

Sorry. I had the code wrong. A similar code works for an array in backwards.

`[].inject(0){_1 * 10 + _2} # => 0 [2, 1].inject(0){_1 * 10 + _2} # => 21 [3, 2, 1].inject(0){_1 * 10 + _2} # => 321 [6, 3, 2, 1].inject(0){_1 * 10 + _2} # => 6321`

I think you'd just need to reverse it, since this result seems backwards. I think it's easy to get the implementation wrong and a handy method to have.

```
6321.digits.inject(0) { _1 * 10 + _2 } #=> 1234
6321.digits.reverse.inject(0) { _1 * 10 + _2 } #=> 4321
```

Using your #reduce strategy, you'd end up with something like the following.

```
class Array
def undigits(base = 10)
reverse.reduce(0) do |acc, digit|
acc * base + digit
end
end
end
```

It's a fairly similar shape to what I had.

```
class Array
def undigits(base = 10)
each_with_index.sum do |digit, exponent|
digit * base**exponent
end
end
end
```

I assumed we'd want to implement it in C if it's accepted, and was just trying to illustrate behavior, but unsure.

#### Updated by shan (Shannon Skipper) over 2 years ago

@sawa (Tsuyoshi Sawada) If this feature is accepted and for whatever reason a Ruby version is used instead of C, yours is more performant Ruby code than mine. It might look like the following. We'd want to implement this in C like Integer#digits, right?

```
class Array
def undigits(base = 10)
base_int = base.to_int
raise TypeError, "wrong argument type #{base_int.class} (expected Integer)" unless base_int.is_a?(Integer)
raise ArgumentError, 'negative radix' if base_int.negative?
raise ArgumentError, "invalid radix #{base_int}" if base_int < 2
reverse.reduce(0) do |acc, digit|
raise MathDomainError, 'out of domain' if digit.negative?
acc * base + digit
end
end
end
```

#### Updated by inopinatus (Joshua GOODALL) about 2 months ago ยท Edited

I'll speak up for this feature. Whilst writing a base58 encoder/decoder today, I was surprised by the lack of an inverse to `Integer#digits`

.

In my benchmarking the reduce/inject variant was considerably faster than the sum variant, especially when we get into bignum territory.

However, for consistency with other conversions, `Integer(array, base)`

should work too, as `Integer(string, base)`

currently does. The latter is already special-cased, so that could be extended to handle an array even if the method above doesn't end up as `Array#to_i`

.