Note that there are some explanatory texts on larger screens.

plurals
  1. POCan I create an array in Ruby with default values?
    primarykey
    data
    text
    <p>Perl is pretty nice about default values:</p> <pre><code>: jmglov@laurana; perl -e '@foo; printf "%d\n", $foo[123]' 0 : jmglov@laurana; perl -e '%foo; printf "%d\n", $foo{bar}' 0 </code></pre> <p>Ruby can do the same, at least for hashes:</p> <pre><code>&gt;&gt; foo = Hash.new(0) =&gt; {} &gt;&gt; foo[:bar] =&gt; 0 </code></pre> <p>But the same seemingly does not work for arrays:</p> <pre><code>&gt;&gt; foo = Array.new(0) =&gt; [] &gt;&gt; foo[123] =&gt; nil &gt;&gt; foo[124] = 0 =&gt; 0 &gt;&gt; foo[456] = 0 =&gt; 0 &gt;&gt; foo[455,456] =&gt; [nil, 0] </code></pre> <p>Is it possible to supply a default value for arrays, so when they are auto-extended, they're filled with 0 instead of nil?</p> <p>Of course I can work around this, but at a cost to expressiveness:</p> <pre><code>&gt;&gt; foo[457,458] = 890, 321 =&gt; [890, 321] &gt;&gt; foo[456] += 789 NoMethodError: You have a nil object when you didn't expect it! You might have expected an instance of Array. The error occurred while evaluating nil.+ &gt;&gt; foo.inject(0) {|sum, i| sum += (i || 0) } =&gt; 1211 &gt;&gt; foo.inject(:+) NoMethodError: You have a nil object when you didn't expect it! You might have expected an instance of Array. The error occurred while evaluating nil.+ </code></pre> <p><strong>Update 1:</strong> One of my colleagues pointed out that I can use <code>#compact</code> to solve the <code>#inject</code> issue, and <code>#to_i</code> to solve the standard element-at-index issue:</p> <pre><code>&gt;&gt; foo.include? nil =&gt; true &gt;&gt; foo.compact.inject(:+) =&gt; 1211 &gt;&gt; foo[456,457] =&gt; [0, 890, 321] &gt;&gt; foo[455..457] =&gt; [nil, 0, 890] &gt;&gt; foo[455..457].map(&amp;:to_i) =&gt; [0, 0, 890] </code></pre> <p><strong>Update 2:</strong> Thanks to <a href="https://stackoverflow.com/users/38765/andrew-grimm">Andrew Grimm</a> for a solution to the <code>+=</code> issue:</p> <pre><code>&gt;&gt; foo = [] =&gt; [] &gt;&gt; def foo.[](i) &gt;&gt; fetch(i) {0} &gt;&gt; end =&gt; nil &gt;&gt; foo[4] =&gt; 0 &gt;&gt; foo =&gt; [] &gt;&gt; foo[4] += 123 =&gt; 123 &gt;&gt; foo =&gt; [nil, nil, nil, nil, 123] </code></pre> <p><strong>Update 3:</strong> this is starting to look like whack-a-mole!</p> <pre><code>&gt;&gt; foo =&gt; [nil, nil, nil, nil, 123] &gt;&gt; foo[-2..-1] TypeError: can't convert Range into Integer </code></pre> <p>But we can deal with that:</p> <pre><code>&gt;&gt; def foo.[](index) &gt;&gt; if index.is_a? Range &gt;&gt; index.map {|i| self[i] } &gt;&gt; else ?&gt; fetch(index) { 0 } # default to 0 if no element at index; will not cause auto-extension of array &gt;&gt; end &gt;&gt; end =&gt; nil &gt;&gt; foo =&gt; [nil, nil, nil, nil, 123] &gt;&gt; foo[-2..-1] =&gt; [nil, 123] </code></pre> <p>I now have to admit (sheepishly) that I'll subclass <code>Array</code> to avoid cluttering my code:</p> <pre><code>class MyClass class ArrayWithDefault &lt; Array def [](index) if index.is_a? Range index.map {|i| self[i] } else fetch(index) { 0 } # default to 0 if no element at index; will not cause auto-extension of array end end end end </code></pre> <p>Thanks for all the creative solutions. TIMTOWTDI indeed!</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload