2017-01-14 2 views
0

У меня есть файл CSV, который мне нужно прочитать и извлечь все строки, которые имеют «created_at» в определенном диапазоне. Сам CSV составляет около 5000 строк в Excel.Как разобрать хэш хэш из файла CSV

Это, как я потянув информацию из файла:

CSV.foreach("sample_data.csv", :headers => true, :header_converters => :symbol, :converters => :all) do |row| 
    data[row.fields[0]] = Hash[row.headers[1..-1].zip(row.fields[1..-1])] 
end 

Вот последний Hash создан после того, как с помощью CSV.foreach:

2760=>{:created_at=>1483189568, :readable_date=>"12/31/2016", :first_name=>"Louise", :last_name=>"Garza", :email=>"[email protected]", :gender=>"Female", :company=>"Cogilith", :currency=>"EUR", :word=>"orchestration", :drug_brand=>"EPIVIR", :drug_name=>"lamivudine", :drug_company=>"State of Florida DOH Central Pharmacy", :pill_color=>"Maroon", :frequency=>"Yearly", :token=>"_", :keywords=>"in faucibus", :bitcoin_address=>"19jTjXLPQUL1nEmHrpqeqM1FdtDFZmUZ2E"}} 

Когда я бегу data[2759].first я получаю:

created_at 
1309380645 

Мне нужно тянуть каждый хэш, где created_at находится между range = 1403321503..1406082945. Я пробовал около двадцати различных методов, используя each и collect на хеше data без успеха. Моя последняя попытка напечатала пустой {} для каждого оригинального хэша.

Я пытаюсь проверить это без успеха:

data.each do |hash| 
    if hash.first.to_s.to_i > 1403321503 && hash.first.to_s.to_i < 1406082945 
    puts hash 
    end 
end 

Я не уверен, как изолировать значение key:created_at, а затем увидеть, если он находится в пределах диапазона. Я также пробовал делать hash.first.to_s.to_i =/== диапазон.

Я могу получить только значение :created_at с помощью data[1].first.last, но когда я пытаюсь использовать его в методе, он не работает.

Вот ссылка на оригинальный CSV: goo.gl/NOjAPo

Это не на моем рабочем компьютере, так что я не могу сделать Pastebin его.

+0

Невозможно рассказать, что происходит из вашего описания. Вам нужно предоставить несколько строк данных, код _runnable_, который производит неправильный ответ, и соответствующий правильный ответ. Например. совсем не ясно, является ли «data» хешем или массивом. Почему бы вам просто не индексировать хэш с символами 'hash [: created_at]'? – Gene

+0

Подсказка: '(x..y) .include? (Z)' является более кратким способом проверки того, что что-то находится внутри заданного диапазона. То, что у вас здесь, является намного более подробным и требует кучи избыточных вызовов методов. – tadman

+0

Еще одна вещь, которая стоит иметь в виду, когда вы делаете Ruby, - это попытаться разбить вашу проблему на ряд цепочек, но простые операции. Например, «отклоняйте» строки, которые вам не нужны, или «выберите» те, которые вы делаете, а затем * «ставит» их. – tadman

ответ

0

Я бы сохранил только строки в хеше data, которые находятся в пределах диапазона. IMO, которая выполняет более сложные действия, поскольку для этого требуется меньше памяти, чем чтение всех данных в data и удаление нежелательных записей на втором этапе.

DATE_RANGE = (1403321503..1406082945) 

CSV.foreach("sample_data.csv", 
      :headers => true, 
      :header_converters => :symbol, 
      :converters => :all) do |row| 
    attrs = Hash[row.headers[1..-1].zip(row.fields[1..-1])] 
    data[row.fields[0]] = attrs if DATE_RANGE.cover?(attrs[:created_at]) 
end 

Это может иметь смысл, чтобы проверить состояние до фактического создания хэша путем проверки DATE_RANGE.cover? против номера столбца (в row.fields[1]created_at?).

+0

Пожалуйста, уважайте ppl с не столь широкими экранами, разделите длинные строки в ответе. – mudasobwa

+0

@ mudasobwa Я думал, что все в порядке, потому что эта линия была предоставлена ​​OP, не вызвала проблему и не изменилась в моем ответе. Извини за это. Я обновил свой ответ с улучшенной длиной строки. – spickermann

+0

Спасибо! Имеет смысл напомнить тем, кто слушает только :) – mudasobwa

0

Применение Enumerable#select

hash.select do |_, v| 
    (1403321503..1406082945) === v[:created_at] 
end 

Здесь мы также использовать Range#=== также известный как случай-равно или тройной равно, чтобы проверить, если значение находится внутри диапазона.

+0

Когда я попытался сделать что-то подобное до того, как он выйдет из строя. Я все-таки работал с .to_s.to_i. Должен ли я добавить .to_s.to_i внутри скобок или снаружи? v [: created_at] .to_s.to_i или v [: created_at.to_s.to_i] –

+0

Преобразование символа в строку и затем в целое число не имеет большого смысла. Непонятно, зачем вы это делаете, но если хотите, преобразуйте все значение 'v [: created_at]'. – mudasobwa

+0

Когда я пытался использовать = или == с диапазоном, я получал ошибки, которые я сравнивал с типом, пытался использовать только .to_i, но это не сработало, поэтому я сделал -> string -> integer, чтобы убедиться, что это целое число. –

Смежные вопросы