下面是針對您的需求量身定製的解決方案。它允許您選擇任意數量的產品或屬性,並查看按權重乘積排序的另一個軸中的值。它可以讓你以CSV格式存儲你的數據,所以你可以保留一個大的Excel文件以供將來調整。
merge_by
,sort_by
和filter_by
方法允許您在獲得結果時指定要應用的塊。
TESTDATA = <<ENDCSV
,red,blue,modern,old fashion,sexy
Jeans myway,0%,100%,30%,30%,70%
Polo Shirt,100%,0%,10%,40%,1%
Bra,100%,0%,100%,0%,100%
ENDCSV
def test
products = RelationTable.load_from_csv(TESTDATA)
p products.find(:col, 'old fashion','modern')
#=> [["Jeans myway", 9.0], ["Polo Shirt", 4.0]]
p products.find(:row, 'Polo Shirt')
#=> [["red", 100.0], ["old fashion", 40.0], ["modern", 10.0]]
p products.find(:col, 'sexy')
#=> [["Bra", 100.0], ["Jeans myway", 70.0], ["Polo Shirt", 1.0]]
p products.find(:row, 'Polo Shirt','Bra')
#=> [["red", 100.0], ["modern", 10.0]]
p products.find(:col, 'sexy','modern')
#=> [["Bra", 100.0], ["Jeans myway", 21.0], ["Polo Shirt", 0.1]]
p products.find(:col, 'red', 'blue')
#=> []
p products.find(:col, 'bogus')
#=> []
end
class RelationTable
def self.load_from_csv(csv)
require 'csv'
data = CSV.parse(csv)
self.new(data.shift[1..-1], data.map{ |r| r.shift }, data)
end
def initialize(col_names=[], row_names=[], weights=[])
@by_col = Hash.new{|h,k|h[k]=Hash.new(0)}
@by_row = Hash.new{|h,k|h[k]=Hash.new(0)}
row_names.each_with_index do |row,r|
col_names.each_with_index do |col,c|
@by_col[col][row] = @by_row[row][col] = weights[r][c].to_f
end
end
# Multiply all weights, sort by weight (descending), only include non-zero
merge_by{ |values| values.inject(1.0){ |weight,v| weight*v/100 }*100 }
sort_by{ |key,value| [-value,key] }
filter_by{ |key,value| value > 0 }
end
def merge_by(&proc); @merge = proc; end
def sort_by(&proc); @sort = proc; end
def filter_by(&proc); @filter = proc; end
def find(row_or_col, *names)
axis = (row_or_col == :row) ? @by_row : @by_col
merge(axis.values_at(*names)).select(&@filter).sort_by(&@sort)
end
private
# Turn an array of hashes into a hash of arrays of values,
# and then merge the values using the merge_by proc
def merge(hashes)
if hashes.length==1
hashes.first # Speed optimization; ignores the merge_by block
else
result = Hash.new{|h,k|h[k]=[]}
hashes.each{ |h| h.each{ |k,v| result[k] << v } }
result.each{ |k,values| result[k] = @merge[values] }
result
end
end
end
test if __FILE__==$0
你說你正在尋找一個比SQL + AR更好的解決方案。你能解釋一下你的「更好」標準嗎?是MySQL/PostgreSQL RDBMS的問題,並會使用基於文件的SQLite數據庫或內存數據庫更好?你是否需要隨時間更新關係,或者加載一次並閱讀它們?你是否只需要執行你描述的查詢(選擇一個屬性並查看按相關性排序的產品)? – Phrogz 2011-03-29 20:41:50
我在尋找更像矩陣的解決方案。看我的編輯。 – Beffa 2011-03-29 21:19:45