开发者

Printing tables with zero values in ruby, ruby syntax

开发者 https://www.devze.com 2023-03-22 11:55 出处:网络
I have two-dimensional hash and I want to print in out to simple html table. There was a query like sele开发者_运维问答ct section,date,count(*) from table group by section,date so values for some inde

I have two-dimensional hash and I want to print in out to simple html table. There was a query like sele开发者_运维问答ct section,date,count(*) from table group by section,date so values for some indexes might not exist.

My ruby code looks like

<% sections.each do sec %>
    <tr>
    <% dates.each do date %>
        <% v = 0 %>
        <% v = @rws[sec][date] unless @rws.nil? || @rws[sec].nil? || @rws[sec][date].nil? %>
        <td><%=v%></td>
    <% end %>
    </tr>
<% end %> 

Is there a better way to work with multi-dimensional hash without endless checks like do something with a unless a.nil? || a[b].nil? || a[b][c].nil? || a[b][c][d].nil? ...?

For example in php I just write:

<?php 
    foreach($sections as $sec)
        foreach($dates as $date)
            echo "<td>" . ($rws[$sec][$date]?$rws[$sec][$date]:0) . "</td>";
?>


There are several ways to avoid it. Easiest one I can think of is to replace:

    <% v = 0 %>
    <% v = @rws[sec][date] unless @rws.nil? || @rws[sec].nil? || @rws[sec][date].nil? %>
    <td><%=v%></td>

with this:

    <td><%= (@rws[sec][date] rescue nil) || 0 %></td>

Which means: display content of hash. if it throws exception for some reason (like calling nil[date]), return nil instead. (nil || 0) returns zero (which is a default value, I assume).

If the hash contains only numbers, you can also use:

    <td><%= (@rws[sec][date] rescue nil).to_i %></td>

nil.to_i returns zero. (Watch out though, "some string".to_i returns also zero.)


You could try manually attaching a default_proc to your @rws inside your controller:

@rws = pile_of_stuff_that_produces_a_hash
@rws.default_proc = proc do |h,k|
    x = { }
    x.default_proc = @rws.default_proc
    h[k] = x
    x
end

Note that the default_proc is "inherited" (x.default_proc = @rws.default_proc) by the newly created hashes so that you get new hashes all the way down. Then, you could do this:

@rws[:where][:is][:pancakes][:house?]

And it would work. The downside is that you'd always get an empty hash when you asked for something that wasn't there so you might have to call emtpy? in places where you would normally call nil?. So you'd have something like this:

<% dates.each do date %>
    <% v = @rws[sec][date] %>
    <td><%= v.is_a?(Hash) && v.empty?? 0 : v %></td>
<% end %>

Depending on your specific circumstances, you might be able to trim v.is_a?(Hash) && v.empty? down to something a bit nicer; for example, if @rws should be numbers all the way down then v.is_a?(Hash) would be sufficient.

This default_proc approach might be too clever for your specific needs but the general technique is worth mentioning.


<%= @rws && @rws[sec] && @rws[sec][date] %>

or with a default value:

<%= (@rws && @rws[sec] && @rws[sec][date]) || 0 %>

That will return the last value. Remember that && does short circuit evaluation, and in ruby, only nil and false evaluate to false.

This only works if intermediate values are always nil or a hash... if @rws[sec] == "foo", then it would give an error.

I like the default_proc solution in a few circumstances, especially for deep hashes, but it may be overkill for small usages...


You can do this:

<% sections.each do sec %>
    <tr>
    <% dates.each do date %>
        <td><%= @rws[sec][date] rescue 0 %></td>
    <% end %>
    </tr>
<% end %> 
0

精彩评论

暂无评论...
验证码 换一张
取 消