我在ruby中有一个嵌套的哈希:
{"Table1"=>{"Acct type"=>{"Expected"=>"ACC", "Actual"=>"ACC"}, "Seq No"=>{"Expected"=>"100.0", "Actual"=>#<BigDecimal:56d0b28,'0.1E3',9(18)>}, "Class"=>{"Expected"=>"AC", "Actual"=>"AC"}}, "Table 2"=>{"Date"=>{"Expected"=>"20140606", "Actual"=>"20130606"}}}
我需要以表格格式显示上面的嵌套哈希 -
Table Field Expected Value Actual Value
Table 1 Acct type ACC ACC
Table 1 Seq No 100.0 100.0
Table 1 Class AC AC
Table 2 Date 20140606 20130606
任何建议/指针都会非常有用。我尝试过使用&#39; tableprint&#39;和&#39; text-table&#39;宝石但却无法获得理想的结果。上述数据是使用ActiveRecord从DB2表中提取的。
答案 0 :(得分:0)
这是一个解决方案:
x = {
"Table1"=>{
"Acct type"=>{"Expected"=>"ACC", "Actual"=>"ACC"},
"Seq No"=>{"Expected"=>"100.0", "Actual"=> 100.00},
"Class"=>{"Expected"=>"AC", "Actual"=>"AC"}
},
"Table 2"=>{
"Date"=> {"Expected"=>"20140606",
"Actual"=>"20130606"}}}
def table_row(row_name, row_values)
[row_name, row_values["Expected"], row_values["Actual"]]
end
def table_rows(table_hash)
table_hash.map do |field_name, field_values|
table_row(field_name, field_values)
end
end
def widest_string_lengths(visual_table)
table_columns_count = visual_table.first.size - 1
0.upto(table_columns_count).map do |index|
columns = visual_table.map { |row| row[index].to_s }
columns.max_by(&:length).length + 2
end
end
def aligned_visual_table(visual_table)
widest_string_items = widest_string_lengths(visual_table)
visual_table.map do |row|
row.each_with_index.map do |cell, index|
cell.to_s.ljust(widest_string_items[index] + 2)
end
end
end
table_headers = ['Table', 'Field', 'Value', 'Actual Value']
# This just turns the hash to array of arrays
visual_table = x.map do |table_name, table_hash|
table_rows(table_hash).map do |table_rows|
table_rows.insert(0, table_name)
end
end.flatten(1).insert(0, table_headers)
puts "*********"
puts aligned_visual_table(visual_table).map(&:join).join("\n")
答案 1 :(得分:0)
您的示例表明存在影响表格外观的未指定参数。例如,列标签“表”和“字段”是左调整的,而“预期值”和“实际值”则不是。此外,“预期值”与“帐户类型”重叠。下面我建议你如何构建表格,但我做出了妥协:左调整所有列标签而不是垂直重叠。
<强>代码强>
def print_table(h, column_labels_and_spacing, table_label)
column_labels = column_labels_and_spacing.map(&:first)
column_spacing = column_labels_and_spacing[0..-2].map(&:last) << 0
rows = h.map { |k,f|
[table_label[k]].product(f.map { |field, g|
[[field, g.values.map(&:to_s)].flatten] }) }
.flat_map { |e| e.map(&:flatten) }.unshift(column_labels)
column_widths = rows.transpose.map { |c| c.max_by(&:size).size }
.zip(column_spacing).map { |a,b| a+b }
rows.each do |row|
row.zip(column_widths).each { |s, width| print s.ljust(width) }
puts
end
end
示例强>
输入
h = {"Table1"=>
{"Acct type"=>{"Expected"=>"ACC", "Actual"=>"ACC"},
"Seq No" =>{"Expected"=>"100.0", "Actual"=>100},
"Class" =>{"Expected"=>"AC", "Actual"=>"AC"}},
"Table 2"=>
{"Date" =>{"Expected"=>"20140606", "Actual"=>"20130606"}}}
column_labels_and_spacing = [["Table", 1], ["Field", 2],
["Expected", 3], ["Actual"]]
table_label = { "Table1"=>"Table 1", "Table 2"=>"Table 2" }
为了简化说明,我将BigDecimal
值转换为Fixnum
。
调用方法
print_table(h, column_labels_and_spacing, table_label)
#-> Table Field Expected Actual
# Table 1 Acct type ACC ACC
# Table 1 Seq No 100.0 100
# Table 1 Class AC AC
# Table 2 Date 20140606 20130606
<强>解释强>
对于上面的例子:
column_labels = column_labels_and_spacing.map(&:first)
#=> ["Table", "Field", "Expected", "Actual"]
column_spacing = column_labels_and_spacing[0..-2].map(&:last) << 0
#=> [1, 2, 3, 0]
a = h.map { |k,f|
[table_label[k]].product(f.map { |field, g|
[[field, g.values.map(&:to_s)].flatten] }) }
# => [[["Table 1", [["Acct type", "ACC", "ACC"]]],
# ["Table 1", [["Seq No", "100.0", "100"]]],
# ["Table 1", [["Class", "AC", "AC"]]]],
# [["Table 2", [["Date", "20140606", "20130606"]]]]]
要了解如何计算a
,请考虑传递给块 1 的第一个键值对h
,该键被赋予块变量{{ 1}}和分配给k
的值:
f
然后该块执行以下计算:
k = "Table1"
f = { "Acct type"=>{ "Expected"=>"ACC", "Actual"=>"ACC" } }
现在让我们继续,计算 b = f.map { |field, g| [[field, g.values.map(&:to_s)].flatten] }
# => [["Acct type", "ACC", "ACC"]]
c = ["Table 1"].product([[["Acct type", "ACC", "ACC"]]])
#=> [["Table 1", [["Acct type", "ACC", "ACC"]]]]
d = c.flatten
#=> ["Table 1", "Acct type", "ACC", "ACC"]
。计算表格主体的行:
a
然后添加列标签:
e = a.flat_map { |e| e.map(&:flatten) }
#=> [["Table 1", "Acct type", "ACC", "ACC"],
# ["Table 1", "Seq No", "100.0", "100"],
# ["Table 1", "Class", "AC", "AC"],
# ["Table 2", "Date", "20140606", "20130606"]]
接下来,计算列宽:
rows = e.unshift(column_labels)
#=> [["Table", "Field", "Expected", "Actual"],
# ["Table 1", "Acct type", "ACC", "ACC"],
# ["Table 1", "Seq No", "100.0", "100"],
# ["Table 1", "Class", "AC", "AC"],
# ["Table 2", "Date", "20140606", "20130606"]]
考虑打印表格的第二行(列标签后的第一行):
f = rows.transpose
#=> [["Table", "Table 1", "Table 1", "Table 1", "Table 2"],
# ["Field", "Acct type", "Seq No", "Class", "Date"],
# ["Expected", "ACC", "100.0", "AC", "20140606"],
# ["Actual", "ACC", "100", "AC", "20130606"]]
g = f.map { |c| c.max_by(&:size).size }
#=> [7, 9, 8, 8]
i = g.zip(column_spacing)
# => [[7, 1], [9, 2], [8, 3], [8, 0]]
column_widths = i.map { |a,b| a+b }
#=> [8, 11, 11, 8]
rows.each do |row|
row.zip(column_widths).each { |s, width| print s.ljust(width) }
puts
end
打印第一个字段:
row = ["Table 1", "Acct type", "ACC", "ACC"]
row.zip(column_widths)
# => [["Table 1", 8], ["Acct type", 11], ["ACC", 11], ["ACC", 8]]
我打印冒号只是为了显示字段宽度。其他字段的印刷方式类似。
1 Ruby 1.9+需要知道哪个键值对首先传递给块。