Ruby заменяет хеш-ключ с помощью регулярных выражений - PullRequest
1 голос
/ 28 июня 2019

Я анализирую файл Excel, используя Creek . Это первая строка (заголовок):

{"A"=>"Date", "B"=>"Portfolio", "C"=>"Currency"}

и все остальные строки:

[ 
 {"A"=>2019-05-16 00:00:00 +0200, "B"=>"TEXT", "C"=>"INR"}, 
 {"A"=>2019-05-20 00:00:00 +0200, "B"=>"TEXT2", "C"=>"EUR"}
]

Моя цель - иметь один и тот же массив, в котором все ключи хеш-функции заменяются ключом mapping с использованием выражения регулярного выражения в значениях хэша mapping.

Например, в заголовке ключи соответствуют этим REGEX:

mapping = {
    date: /Date|Data|datum|Fecha/,
    portfolio_name: /Portfolio|portafoglio|Portfolioname|cartera|portefeuille/,
    currency: /Currency|Valuta|Währung|Divisa|Devise/
    }

Поэтому мне нужно заменить все строки данных следующим образом:

[ 
  {"date"=>2019-05-16 00:00:00 +0200, "portfolio_name"=>"TEXT", "currency"=>"INR"}, 
  {"date=>2019-05-20 00:00:00 +0200, "portfolio_name"=>"TEXT2", "currency"=>"EUR"}
]

Ответы [ 2 ]

4 голосов
/ 28 июня 2019

Определить имена столбцов на отдельном шаге. Промежуточное отображение будет выглядеть как {"A"=>:date, "B"=>:portfolio_name, "C"=>:currency}, и тогда вы сможете преобразовать массив данных.

Это довольно просто:

header_mapping = header.transform_values{|v|
  mapping.find{|key,regex| v.match?(regex) }&.first || raise("Unknown header field #{v}")
}

rows.map{|row|
  row.transform_keys{|k| header_mapping[k].to_s }
}

Код требует Ruby 2.4+ для нативного Hash#transform_* или ActiveSupport

1 голос
/ 28 июня 2019

TL: DR;

require 'time'

mappings = {
  date: /Date|Data|datum|Fecha/,
  portfolio_name: /Portfolio|portafoglio|Portfolioname|cartera|portefeuille/,
  currency: /Currency|Valuta|Währung|Divisa|Devise/
}

rows = [
  {"A"=>"Date", "B"=>"Portfolio", "C"=>"Currency"},
  {"A"=>Time.parse('2019-05-16 00:00:00 +0200'), "B"=>"TEXT", "C"=>"INR"}, 
  {"A"=>Time.parse('2019-05-20 00:00:00 +0200'), "B"=>"TEXT2", "C"=>"EUR"}
]

header_row = rows.first

mapped_header_row = header_row.inject({}) do |hash, (k, v)|
  mapped_name = mappings.find do |mapped_name, regex|
    v.match? regex
  end&.first

  # defaults to `v.to_sym` (Header Name), if not in mappings
  # you can also raise an Exception here instead if not in mappings, depending on your expectations
  hash[k] = mapped_name || v.to_sym 
  hash
end

mapped_rows = rows[1..-1].map do |row|
  new_row = {}
  row.each do |k, v|
    new_row[mapped_header_row[k]] = v
  end
  new_row
end

puts mapped_rows
# => [
#      {:date=>2019-05-16 00:00:00 +0200, :portfolio_name=>"TEXT", :currency=>"INR"},
#      {:date=>2019-05-20 00:00:00 +0200, :portfolio_name=>"TEXT2", :currency=>"EUR"}
#    ]

Дано:

require 'time'

mappings = {
  date: /Date|Data|datum|Fecha/,
  portfolio_name: /Portfolio|portafoglio|Portfolioname|cartera|portefeuille/,
  currency: /Currency|Valuta|Währung|Divisa|Devise/
}

rows = [
  {"A"=>"Date", "B"=>"Portfolio", "C"=>"Currency"},
  {"A"=>Time.parse('2019-05-16 00:00:00 +0200'), "B"=>"TEXT", "C"=>"INR"}, 
  {"A"=>Time.parse('2019-05-20 00:00:00 +0200'), "B"=>"TEXT2", "C"=>"EUR"}
]

Шаги:

  1. Сначала извлекаем первую строку, чтобы получить имена столбцов.

    header_row = rows.first
    puts header_row
    # => {"A"=>"Date", "B"=>"Portfolio", "C"=>"Currency"}
    
  2. Нам нужно перебрать каждую из хэш-пар: (ключ, значение), и нам нужно выяснить, соответствует ли «значение» какой-либо из наших mappings переменных.

    Короче говоря, для этого шага нам нужно как-то преобразовать (т.е.):

    header_row = {"A"=>"Date", "B"=>"Portfolio", "C"=>"Currency"}

    в

    mapped_header_row = {"A"=>"date", "B"=>"portfolio_name", "C"=>"currency"}

    И так ...

    mapped_header_row = header_row.inject({}) do |hash, (k, v)|
      mapped_name = mappings.find do |mapped_name, regex|
        v.match? regex
      end&.first
    
      # defaults to `v.to_sym` (Header Name), if not in mappings
      # you can also raise an Exception here instead if not in mappings, depending on your expectations
      hash[k] = mapped_name || v.to_sym 
      hash
    end
    
    puts mapped_header_row
    # => {"A"=>"date", "B"=>"portfolio_name", "C"=>"currency"}
    

    См. inject

    См. find

  3. Теперь, когда у нас есть mapped_header_row (или «сопоставленные» метки / имена для каждого столбца), мы можем просто обновить все «ключи» 2-й строки до последней строки с помощью «сопоставленное» имя: ключи «A», «B» и «C» ... должны быть заменены соответственно на «date», «portfolio_name» и «currency»

    # row[1..-1] means the 2nd element in the array until the last element
    mapped_rows = rows[1..-1].map do |row|
      new_row = {}
      row.each do |k, v|
        new_row[mapped_header_row[k]] = v
      end
      new_row
    end
    
    puts mapped_rows
    # => [
    #      {:date=>2019-05-16 00:00:00 +0200, :portfolio_name=>"TEXT", :currency=>"INR"},
    #      {:date=>2019-05-20 00:00:00 +0200, :portfolio_name=>"TEXT2", :currency=>"EUR"}
    #    ]
    

    См. map

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...