Project

General

Profile

Actions

Feature #19830

open

Allow `Array#transpose` to take an optional size argument

Added by tomstuart (Tom Stuart) 9 months ago. Updated 9 months ago.

Status:
Open
Assignee:
-
Target version:
-
[ruby-core:114342]

Description

One benefit of supplying an initial value to Enumerable#inject is that it avoids an annoying edge case when the collection is empty:

>> [1, 2, 3].inject(:+)
=> 6 # good

>> [].inject(:+)
=> nil # bad

>> [].inject(0, :+)
=> 0 # good

A similar edge case exists for Array#transpose:

>> [[1, :a], [2, :b], [3, :c]].transpose
=> [[1, 2, 3], [:a, :b, :c]] # good

>> [].transpose
=> [] # bad

Although no explicit nil is produced here, the subtle problem is that the caller may assume that the result array contains arrays, and that assumption leads to nils in the empty case:

>> [[1, :a], [2, :b], [3, :c]].transpose.then { _2.join }
=> "abc"

>> [].transpose.then { _2.join }
undefined method `join' for nil:NilClass (NoMethodError)

If we allow Array#transpose to take an optional argument specifying the size of the result array, we can use this to always return an array of the correct size:

>> [[1, :a], [2, :b], [3, :c]].transpose(2)
=> [[1, 2, 3], [:a, :b, :c]] # good

>> [].transpose(2)
=> [[], []] # good

By avoiding an unexpectedly empty result array, we also avoid unexpected downstream nils:

>> [[1, :a], [2, :b], [3, :c]].transpose(2).then { _2.join }
=> "abc"

>> [].transpose(2).then { _2.join }
=> ""

Here is a patch which adds an optional argument to Array#transpose to support the above usage: https://github.com/ruby/ruby/pull/8167

Something similar was requested eleven years ago in #6852. I believe this feature addresses the problem expressed in that issue without compromising backward compatibility with existing callers of #transpose.

Actions

Also available in: Atom PDF

Like2
Like0Like1Like0