彎,讓我先提出一些關於您的解決方案的意見。 (然後,我將提供同樣採用Array#product
的替代方法。)這裏是你的代碼,格式化,露出結構:因爲你不願意來定義中間變量
[nil].product(*@dimensions.map { |d| (0...d[:values].size).to_a })
.map(&:compact)
.map(&:flatten)
.each do |data_idxs|
row = data_idxs.each_with_index.map
{ |data_idx, dim_idx| @dimensions[dim_idx][:values][data_idx] }
row << data_idxs.inject(@data) { |data, idx| data[idx] }
puts row.join(" |\t ")
end
- 我覺得很混亂,部分。我首先計算
product
的參數並將其分配給變量x
。我說x
,因爲很難提出一個好名字。然後,我會將product
的結果分配給另一個變量,如:y = x.shift.product(x)
或(如果您不想要x
修改)y = x.first.product(x[1..-1)
。這避免了需要compact
和flatten
。
- 我發現變量名稱的選擇令人困惑。問題的根源在於
@dimensions
和@data
都以d
開頭!如果你簡單地使用@vals
而不是@data
,這個問題會大大減少。
- 將
data_idxs.each_with_index.map
寫爲data_idxs.map.with_index
會比較習慣。
- 最後,但最重要的是,您決定使用索引而不是數值本身。 不要這樣做。只是不要那樣做。這不僅是不必要的,但它會讓你的代碼變得如此複雜以至於很難解決這個問題,這很耗費時間,而且令人頭痛。
考慮是多麼容易被操縱的數據沒有任何參考指數:
vals = @dimensions.map {|h| h.values }
# [["speed", [0..20, 20..40, 40..60 ],
# ["distance", [0..50, 50..100, 100..150]]
attributes = vals.map(&:shift)
# ["speed", "distance"]
# vals => [[[0..20, 20..40, 40..60]],[[0..50, 50..100, 100..150]]]
vals = vals.flatten(1).map {|a| a.map(&:to_s)}
# [["0..20", "20..40", "40..60"],["0..50", "50..100", "100..150"]]
rows = vals.first.product(*vals[1..-1]).zip(@data.flatten).map { |a,d| a << d }
# [["0..20", "0..50", 1],["0..20", "50..100", 2],["0..20", "100..150", 3],
# ["20..40", "0..50", 4],["20..40", "50..100", 5],["20..40", "100..150", 6],
# ["40..60", "0..50", 7],["40..60", "50..100", 8],["40..60", "100..150", 9]]
我會以這樣的方式解決這個問題,你可以有任意數量的屬性(即「速度「,」距離「,...)和格式化將由數據決定:
V_DIVIDER = ' | '
COUNT = 'count'
attributes = @dimensions.map {|h| h[:name]}
sd = @dimensions.map { |h| h[:values].map(&:to_s) }
fmt = sd.zip(attributes)
.map(&:flatten)
.map {|a| a.map(&:size)}
.map {|a| "%-#{a.max}s" }
attributes.zip(fmt).each { |a,f| print f % a + V_DIVIDER }
puts COUNT
prod = (sd.shift).product(*sd)
flat_data = @data.flatten
until flat_data.empty? do
prod.shift.zip(fmt).each { |d,f| print f % d + V_DIVIDER }
puts (flat_data.shift)
end
如果
@dimensions = [{:name => "speed", :values => [0..20,20..40,40..60] },
{:name => "volume", :values => [0..30, 30..100, 100..1000]},
{:name => "distance", :values => [0..50, 50..100, 100..150] }]
這顯示:
speed | volume | distance | count
0..20 | 0..30 | 0..50 | 1
0..20 | 0..30 | 50..100 | 2
0..20 | 0..30 | 100..150 | 3
0..20 | 30..100 | 0..50 | 4
0..20 | 30..100 | 50..100 | 5
0..20 | 30..100 | 100..150 | 6
0..20 | 100..1000 | 0..50 | 7
0..20 | 100..1000 | 50..100 | 8
0..20 | 100..1000 | 100..150 | 9
其工作原理如下(與@dimensions
原始值,剛走兩個屬性「速度」和「距離」):
Attributes
是屬性的列表。作爲一個陣列,它保持它們的順序:
attributes = @dimensions.map {|h| h[:name]}
# => ["speed", "distance"]
我們從@dimensions
拔出範圍,並將其轉換爲字符串:
sd = @dimensions.map { |h| h[:values].map(&:to_s) }
# => [["0..20", "20..40", "40..60"], ["0..50", "50..100", "100..150"]]
接下來我們計算字符串在格式化所有列,但最後:
fmt = sd.zip(attributes)
.map(&:flatten)
.map {|a| a.map(&:size)}
.map {|a| "%-#{a.max}s" }
# => ["%-6s", "%-8s"]
這裏
sd.zip(attributes)
# => [[["0..20", "20..40", "40..60"], "speed" ],
# [["0..50", "50..100", "100..150"], "distance"]]
8
"%-8s"
等於列標籤長度的最大值distance
(8)和distance
範圍的最長字符串表示的長度(對於"100..150"
也是8)的最大長度。格式化字符串中的-
左鍵調整字符串。
我們現在可以打印頭:
attributes.zip(fmt).each { |a,f| print f % a + V_DIVIDER }
puts COUNT
speed | distance | count
要打印剩餘行,我們構建含有前兩列中的內容的陣列。該數組的每個元素對應於一個行表中的:
prod = (sd.shift).product(*sd)
# => ["0..20", "20..40", "40..60"].product(*[["0..50", "50..100", "100..150"]])
# => ["0..20", "20..40", "40..60"].product(["0..50", "50..100", "100..150"])
# => [["0..20", "0..50"], ["0..20", "50..100"], ["0..20", "100..150"],
# ["20..40", "0..50"], ["20..40", "50..100"], ["20..40", "100..150"],
# ["40..60", "0..50"], ["40..60", "50..100"], ["40..60", "100..150"]]
我們需要flaten @data:
flat_data = @data.flatten
# => [1, 2, 3, 4, 5, 6, 7, 8, 9]
第一次通過until do
環,
r1 = prod.shift
# => ["0..20", "0..50"]
# prod now => [["0..20", "50..100"],...,["40..60", "100..150"]]
r2 = r1.zip(fmt)
# => [["0..20", "%-6s"], ["0..50", "%-8s"]]
r2.each { |d,f| print f % d + V_DIVIDER }
0..20 | 0..50 |
puts (flat_data.shift)
0..20 | 0..50 | 1
# flat_data now => [2, 3, 4, 5, 6, 7, 8, 9]
特,我編輯了我的解決方案,爲您提供一些意見。 –