Есть ли база данных или структура данных для Ruby для реализации матриц отношений? - PullRequest
1 голос
/ 29 марта 2011

У меня есть очень простой набор данных

  • продукты
  • атрибуты
  • кросс-таблица: релевантность атрибутов для продукта

                      red    blue   modern   old fashion  (50+ Entries)
         Jeans myway    0%   100%    30%       30%
         Polo Shirt   100%     0%    10%       40%
         (500+ Entries)
    

В приложении вы выбираете атрибуты, такие как красный, синий, .. и сортируете продукты по релевантности.

Лучший способ хранения данных - этоЕсть хорошая структура данных (библиотека) для ruby?

(Не подскажите, как реализовать это с традиционными 3 таблицами sql и активной записью. Я уже знаю, как. Я ищу лучшее решение.)

Одним из способов может быть использование хэша:

"red" => {"Jeans myway" => 0, "Polo Shirt" => 100}, "blue" => {..

- это хороший способ и как мне сохранить его в файл?

[править] Лучшее решение:Если я возьму реляционную базу данных, мне придется разделить матрицу на 3 таблицы products, attribute, attribute_products.Я хотел бы сохранить его в одной таблице / матрице и искать / использовать его как матрицу.

Например, я хочу выбрать продукты, в которых атрибуты 'old fashion', 'modern' отсортированы (> 0).по релевантности вернул бы «Джинсы мой 0,09», «Рубашка поло 0,04».(Релевантность рассчитывается умножением.)

1 Ответ

2 голосов
/ 30 марта 2011

Вот решение с учетом ваших потребностей. Он позволяет выбрать произвольное количество продуктов или атрибутов и просмотреть значения по другой оси, отсортированные по произведению весов. Он позволяет хранить ваши данные в формате 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...