Ruby和CSV -如何在过滤行后获取列值

vyswwuz2  于 2023-02-18  发布在  Ruby
关注(0)|答案(2)|浏览(178)

我解析了一个标头为ID、Name和Address的CSV文件。我需要在数据中查找具有特定ID和Name的行。找到该行后,我需要访问Address值。

data = CSV.parse(my_csv, headers: true)

rows = data.select { |row| row['ID'] == someId } //ids are not unique
row = rows.select { |row| row['Name'] == name } //names are unique

如何得到该行数据中Address的值?row[2]不起作用。

kgqe7b3p

kgqe7b3p1#

我需要在数据中查找具有特定ID和Name的行。
您可以在单个select()中合并任意多个条件:

rows = data.select {|row| row['ID'] == someId && row['Name'] == name}

事实上,你可以根据自己的意愿将这个布尔语句变得简单或复杂,你需要确定得到你想要的结果所需的确切的布尔逻辑。
我需要访问地址值。
要获取所选每行的'Address'列,请使用map()

addresses = rows.map {|row| row['Address']}

要选择第一行的'Address'列:

rows[0]['Address']

不过,最后一个要小心,如果rows为空,则会导致错误。

mwngjboj

mwngjboj2#

让我们首先创建一些测试数据。

my_csv = <<~_
ID,Name,Address
1,cat,Mars
2,dog,Jupyter
1,dog,Venus
_
  #=> "ID,Name,Address\n1,cat,Mars\n2,dog,Jupyter\n1,dog,Venus\n"
puts my_csv
ID,Name,Address
1,cat,Mars
2,dog,Jupyter
1,dog,Venus

因为'Names'的值是唯一的,所以我们可以使用Enumerable #find,它会在其块中的条件计算true时立即终止。
一个二个一个一个
注意,如果没有行满足阻塞条件,则row被分配为nil
我们可以通过使用Safe Navigation Operator&来缩短时间。

def find_addr(csv_str, id, name)
  CSV.parse(csv_str, headers: true).find do |row|
    row['ID'] == id && row['Name'] == name
  end&.[]('Address')
end
find_addr(my_csv, "1", "cat") #=> "Mars"
find_addr(my_csv, "1", "dog") #=> "Venus"
find_addr(my_csv, "2", "dog") #=> "Jupyter"
find_addr(my_csv, "2", "pig") #=> nil

注意,在使用安全导航操作符时,我们不能使用 * syntacticsugar * 版本的方法,这里

...end&['Address']

会引发异常。
如果find_addr返回nil,表明数据有问题,我们可以在代码中处理,或者在上面的第二个方法中删除安全导航操作符,如果没有行满足所需的条件,这将导致引发NoMethodError异常。

相关问题