## Feature #12116

open### `Fixnum#divmod`, `Bignum#divmod` with multiple arguments

**Description**

Sometimes, I need to apply `divmod`

repeatedly. For example, in order to convert a number expressing seconds into approx year, day, hour, minutes, seconds (approx in the sense of ignoring leap day and leap second), I can repeatedly apply `divmod`

:

```
seconds = 289342751
minutes, seconds = seconds.divmod(60) # => [4822379, 11]
hours, minutes = minutes.divmod(60) # => [80372, 59]
days, hours = hours.divmod(24) # => [3348, 20]
years, days = days.divmod(365) # => [9, 63]
```

so that I get that 289342751 seconds is approx 9 years 63 days 20 hours 59 minutes and 11 seconds. But it is cumbersome to do all that. It would be convenient if `divmod`

can take multiple arguments so that the conventional `divmod`

is applied from the right-most argument to the left, returning the above result at once:

```
289342751.divmod(365, 24, 60, 60) # => [9, 63, 20, 59, 11]
```

In general, when `n`

arguments are passed to the proposed `divmod`

, an array of `n + 1`

elements should be returned.

Another use case is nested arrays. Some people tend to express a matrix as a nested array, and try to access the innermost elements using multiple indices. To list the coordinates of the occurrences of `1`

, one may do:

```
m = [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
]
a = []
m.each_with_index do |row, i|
row.each_with_index do |e, j|
a.push([i, j]) if e == 1
end
end
a # => [[0, 0], [1, 1], [2, 2]]
```

But it is often easier to have a flat array and use `divmod`

with it:

```
m = [
1, 0, 0,
0, 1, 0,
0, 0, 1,
]
m.each.with_index.select{|e, _| e == 1}.map{|_, i| i.divmod(3)} # => [[0, 0], [1, 1], [2, 2]]
```

However, once the nesting achieves another level, it becomes cumbersome. Instead of using a nested array:

```
t = [
[
["a", "b"],
["c", "d"],
],
[
["a", "b"],
["c", "d"],
],
]
```

one can keep using a flat array, but that would require repeated application of `divmod`

to covert between the flat index and the nested index. The proposed feature would also help in such case.

#### Updated by shyouhei (Shyouhei Urabe) over 6 years ago

Huge +1 to this. The use case is obvious.

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

Shyouhei Urabe wrote:

Huge +1 to this. The use case is obvious.

Thank you.

Still another use case is converting UNIX file permission from octal form to binary form.

```
r, w, x = 5.divmod(2, 2) # => [1, 0, 1]
r, w, x = 5.divmod(2, 2).map(&:positive?) # => [true, false, true]
```

#### Updated by Eregon (Benoit Daloze) over 6 years ago

Nice idea! +1

#### Updated by marcandre (Marc-Andre Lafortune) over 6 years ago

Very nice!

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

My proposal remains as I proposed above, but I just wanted to note that there is another natural way to generalize the notion of `divmod`

with multiple divisors, and that people be aware of the difference.

- The proposed generalization: The list of divisors are applied from
**the right to the left**on the**quotient**of the previous application of the conventional`divmod`

. Examples are already given. - The other generalization of the notion: The list of divisors are applied from
**the left to the right**on the**remainder**of the previous application of the conventional`divmod`

.

An example of the second notion is a vending machine program. Suppose the change to give back is 937 yen. There are 500-, 100-, 50-, 10-, 5-, and 1-yen coins. The change is calculated as follows:

```
937.divmod(500) # => [1, 437]
437.divmod(100) # => [4, 37]
37.divmod(50) # => [0, 37]
37.divmod(10) # => [3, 7]
7.divmod(5) # => [1, 2]
```

This gives us `[1, 4, 0, 3, 1, 2]`

, which represents that one 500-yen, four 100-yen, zero 50-yen, three 10-yen, one 5-yen, and two 1-yen coins should be payed back to give the change.

This second notion may have other use cases such as converting numerals to roman numerals.

I still feel that the first notion, which I proposed, will find more use cases than the second one, so I retain my proposal as is, but was wondering if someone might think differently.

#### Updated by mrkn (Kenta Murata) over 6 years ago

**Related to***Feature #4787: Integer#each_modulo(n)*added

#### Updated by mrkn (Kenta Murata) over 6 years ago

**Related to***Feature #12447: Integer#digits for extracting digits of place-value notation in any base*added