Было бы лучше использовать коллекцию в этой ситуации? - PullRequest
1 голос
/ 08 января 2009

Я только начинаю использовать Ruby и написал немного кода для базового анализа файла CSV (Line - базовый класс, для краткости опущен):

class File

  def each_csv
    each do |line|
      yield line.split(",")
    end
  end

end

lines = Array.new

File.open("some.csv") do |file|
  file.each_csv do |csv| 
    lines << Line.new(:field1 => csv[0], :field2 => csv[1])
  end
end

У меня такое ощущение, что мне лучше было бы как-то использовать collect, чем помещать каждый Line в массив, но я не могу понять, как это сделать.

Может кто-нибудь показать мне, как это сделать, или все отлично, как есть?

Редактировать: Я должен был дать понять, что на самом деле я не собираюсь использовать этот код в производстве, это больше для привыкания к конструкциям языка. Тем не менее, полезно знать, что есть библиотеки, которые делают это правильно.

Ответы [ 4 ]

4 голосов
/ 08 января 2009

Вот (возможно, дикая) идея: используйте класс Struct вместо того, чтобы использовать свой собственный простой класс POD. Но от этого вы хотите иметь конструктор, который принимает все аргументы, которые могут быть сгенерированы из данных файла.

Line = Struct.new(:field1, :field2, :field3)

Тогда в основе алгоритма вы хотите что-то вроде:

File.open("test.csv").lines.inject([]) do |result, line|
    result << Line.new(line.split(",", Line.length))
end

или быть немного более кратким и функциональным:

lines = File.open("test.csv").lines.map { |line| Line.new(line.split(",", Line.length)) }

Честно говоря, я не очень много использовал класс Struct, но я должен это делать, и я, вероятно, буду реорганизовывать материал, уже написанный для его использования. Это позволяет вам получить доступ к переменным по их именам, таким как:

Line.field1 = blah
Line.field2 = 1

Рубин Структура класс.

Таким образом, чтобы на самом деле ответил на ваш вопрос , и, посмотрев выше на код, я бы сказал, что было бы намного проще использовать collect / map для выполнения вычислений. Функция map вместе с inject очень мощная, и я считаю, что использую их довольно часто.

2 голосов
/ 08 января 2009

Не знаю, знаете ли вы об этом, но у ruby ​​есть собственный класс для анализа и записи файлов CSV.

Я нашел пример использования collect для превращения csv-файла в массив хэшей.

def csv_to_array(file_location)
  csv = CSV::parse(File.open(file_location, 'r') {|f| f.read })
  fields = csv.shift
  csv.collect { |record| Hash[*(0..(fields.length - 1)).collect {|index| [fields[index],record[index].to_s] }.flatten ] }
end

Этот пример взят из этой статьи .

Если вы не знакомы с понятием *, оно в основном убирает внешние скобки [], превращая массив в разделенный запятыми список его элементов.

1 голос
/ 08 января 2009

Вы смотрели на FasterCSV, он делает то, что вы пытаетесь сделать здесь, наряду с тем, что справляетесь с некоторой смертью мозга, которую вы найдете в некоторых файлах CSV

0 голосов
/ 08 января 2009

Посмотрите, как это работает для вас (функциональное программирование - это весело!):

Попробуйте использовать инъекцию. Inject принимает в качестве параметра начальный «аккумулятор», а затем блок из двух параметров:

[1,2,3].inject(0) { |sum,num| sum+num }

естественно 6

[1,2,3].inject(5) { |sum,num| sum+num }

составляет 11

[1,2,3].inject(2) { |sum,num| sum*num }

составляет 12

К вопросу:

class Line
  def initialize(options)
    @options = options
  end

  def to_s
    @options[:field1]+" "+@options[:field2]
  end
end

File.open("test.csv").lines.inject([]) do |lines,line|
  split = line.split(",")
  lines << Line.new(:field1 => split[0],:field2 => split[1])
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...