【问题标题】:How to replace values of a specified column in a CSV using Ruby?如何使用 Ruby 替换 CSV 中指定列的值?
【发布时间】:2015-09-07 08:57:34
【问题描述】:

我有一个 CSV,其中第一列给出了工作日。但问题是我需要在 MATLAB 中使用 CSV,它不允许字符串值。所以,我想在 CSV 中将周日转换为 7,...,周一转换为 1。

但我似乎无法在 Ruby 中找到一种方法来做到这一点。而且我也无法手动打开excel,因为文件很大。具体来说,我在弄清楚如何在 Ruby 中访问和指向我想要的特定列的语法时遇到了问题。例如,如果文件已经在 MATLAB 中加载,并且由于某种原因仍需要我将工作日转换为数字,我会编写如下简单代码:

for i=1:length(Columns(:,1))
    if Columns(i,1)=='sunday'
        Columns(i,1)=7
    elseif Columns(i,1)=='saturday'
        Columns(i,1)=6
    elseif Columns(i,1)=='friday'
        Columns(i,1)=5
    elseif Columns(i,1)=='thursday'
        Columns(i,1)=4
    elseif Columns(i,1)=='wednesday'
        Columns(i,1)=3
    elseif Columns(i,1)=='tuesday'
        Columns(i,1)=2
    elseif Columns(i,1)=='monday'
        Columns(i,1)=1
    end
end

所以,我在弄清楚这个语句的 Ruby 等效项时遇到了问题:

for i=1:length(Columns(:,1))

感谢任何帮助。谢谢。

【问题讨论】:

    标签: ruby-on-rails ruby excel matlab csv


    【解决方案1】:

    Ruby 中有两个不错的 CSV 库,根据您所说的,我假设 CSV 文件没有标题(如果有,SmarterCSV 会让事情变得更容易一些)。

    也就是说,你想获得第一列:

    require 'csv'
    
    your_csv = CSV.open("your_csv.csv")
    # This is the line you wanted:
    first_column = your_csv.map(&:first)
    
    # Then to do the weekday conversion (with a Hash):
    convert_weekdays = { "sunday" => 1, "monday" => 2, "tuesday" => 3, "wednesday" => 4, "thursday" => 5, "friday" => 6, "saturday" => 7 }
    
    converted = first_column.map { |row| convert_weekdays[row] }
    

    不确定这是否正是您想要的,有很多方法可以在 Ruby 中处理 CSV 文件。

    要保存 CSV,您需要使用 CSV.open 打开一个新的(或相同的)CSV 文件:

    your_csv = CSV.open("your_csv.csv")
    CSV.open("saved_csv.csv", "w") do |csv|
      your_csv.each { |row| csv << [convert_weekdays[row.first], *row[1...row.size]] }
    end
    

    抱歉,这有点不雅,用 Ruby 编写 CSV 并不总是最简单的事情!请注意花括号{}do end 相同,但通常在内部块只有一行时使用。

    编辑:这种方法对于大文件可能会快一点:

    your_csv = CSV.parse("your_csv.csv")
    convert_weekdays = { "sunday" => 1, "monday" => 2, "tuesday" => 3, "wednesday" => 4, "thursday" => 5, "friday" => 6, "saturday" => 7 }
    by_columns = your_csv.transpose
    by_columns.first.map! { |row| convert_weekdays[row] }
    CSV.open("saved_csv.csv", "w") do |csv|
      by_columns.transpose.each { |row| csv << row }
    end
    

    这样,您将 CSV 加载为二维数组,对其进行转置,然后仅对第一列进行操作。

    【讨论】:

    • 你好。非常感谢,我正在运行代码,让我们看看它是否有效。 &amp;: 是什么,它是如何工作的?它是要在同一个 csv 中编辑,还是用一些默认名称创建一个新的 csv?我问是因为到目前为止,当代码运行时,当我刷新文件夹时,我看不到文件的“修改日期”部分有任何变化。
    • 不,这只是要创建一个本地对象。您必须自己重新保存 CSV。尝试使用CSV.open。这个评论的事情并没有让我详细说明,我会添加到我的答案中。
    • 对于&amp;,这代表符号到proc。您可以在 ruby​​ 中将其作为块传递,类似于 your_csv.map { |row| row.first },当您在每个对象上调用单个方法时,&amp;: 是一个方便的快捷方式。 :first 是代表first 方法的符号,&amp; 使map 将其解释为一个块。
    • 哇。非常感谢。有用。我需要一些时间来理解它。但是如果我理解正确的话,在 Ruby 中没有办法索引数组,对吧?我的意思是,可以按照您上面提到的方式进行操作,但是这里不可能进行Array(i,j) 操作,对吗?换句话说,如果没有某种与这些特定值相关的共同条件,就不能只访问数组的某些特定值。我说的对吗?
    • 顺便说一下,我刚刚注意到,如果your_csv 的大小较小,则创建新文件的速度实际上会更快,而如果your_csv 的大小较小,则速度会慢得多巨大的。我的意思是,如果您刷新文件夹并看到文件大小发生变化,那么如果原始 csv 较小,则速度会更快,反之亦然。就像,一个 csv 大小的 3 倍需要 10 倍的时间。为什么会这样?
    猜你喜欢
    • 1970-01-01
    • 2021-11-28
    • 2015-11-05
    • 1970-01-01
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    • 2011-02-21
    • 2014-03-05
    相关资源
    最近更新 更多