質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.47%

  • Ruby

    7943questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

csvへの出力

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 1,134

hkhk0

score 8

実現したいこと

下記のような内容のcsvファイルを出力させたいと思っています。

"name","score1","socore2","average"
"A","40","69","54.5"
"B","19","18","18.5"
"C","20","12","16"
"D","70","41","55.5"
"E","77","78","77.5"

試したこと

sample.csv

"name","score01","score02"
"A","40","69"
"B","19","18"
"C","20","12"
"D","70","41"
"E","77","78"
require "csv"
infile = "sample.csv"
outfile = "sample_r.csv"

csv = CSV.read(infile)
header = csv.first, "average"
i = 0
CSV.open(outfile, "w", :headers => header, :write_headers => true) do |f|
 CSV.foreach(infile, headers: true) do |row| 
    csvtable = CSV.table(infile) 
    ave = (row[1].to_f + row[2].to_f) / 2
    f << [csvtable[i], ave]
    i = i + 1
 end
end


実行結果
sample_r.csv

"[""name"", ""score01"", ""score02""]",average
"A,40,69
",54.5
"B,19,18
",18.5
"C,20,12
",16.0
"D,70,41
",55.5
"E,77,78
",77.5

不自然なコードかもしれませんが、この様な書き方で出力させるにはどのように修正すればよろしいでしょうか?
また、中途半端に改行されたり[]や”が入ってしまうのはなぜでしょうか?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

0

こうすればいいかと

require "csv"
infile = "sample.csv"
outfile = "sample_r.csv"

csv = CSV.read(infile)
header = csv.first << "average"
i = 0
CSV.open(outfile, "w", :headers => header, :write_headers => true, :force_quotes => true) do |f|
 CSV.foreach(infile, headers: true) do |row| 
    csvtable = CSV.table(infile)
    ave = (row[1].to_f + row[2].to_f) / 2
    f << (csvtable[i] << ave)
    i = i + 1
 end
end


型の違いが今回のバグの原因みたいです。
csv.firstは["name","score01","score02"]という配列で"avarage"は文字列ですね。
CSV gemは配列を改行のキーとしている節があるので、ヘッダーの謎の改行と[]は配列の中に配列が入っちゃったからでしょう。
また、レコードの謎の改行は[CSVオブジェクト,文字列]の配列が原因でしょう。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/21 16:43

    ご回答有り難うございます。お陰様で解決することができました。なるほど、[CSVオブジェクト,文字列]ってなってしまってたのですね。

    キャンセル

0

header = csv.first, "average" で、CSVの1行目と、文字を書き込んでます。""average""としても、カギカッコが残ります。文字変数に csv.first & "average"みたいな1行とするでしょうか、私なら。
それと、2回書き込んでます。これも、一つにして1回書き込むと良いかも。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/21 14:54

    ご回答有り難うございます。改めて検討させていただきます。

    キャンセル

0

意図しない形式になるのは、まずヘッダについては、csv.first, "average"がおかしいです。
値としては[["name", "score01", "score02"], "average"]になって、二重の配列なのでcsvに書き出すと結果のようになってしまいます。

データ行は、f << [csvtable[i], ave]の部分が、f << [csvtable[i], ave].to_sつまりf << csvtable[i].to_s + ave.to_sと同様になるためです。csvtable[i].to_sで、改行が付くようです。

また、infileのループの中で、csvtable = CSV.table(infile)と毎回infileをファイル全部読み出すのはおかしいです。そもそも不要だし、読むにしてもループの外で。

ヘッダの処理を今ひとつマスターできてませんが、とりえあえずこんな感じで。

CSV.open(infile) do |csv|
  hdr = csv.gets
  hdr << "average"
  CSV.open(outfile, "w", force_quotes: true, write_headers: true, headers: hdr) do |f|
    csv.each do |row|
      ave = (row[1].to_f + row[2].to_f) / 2
      row << ave
      f << row
    end
  end
end

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/21 16:45

    ご回答有り難うございます。詳しい解説を有り難うございます。とても参考になりました。

    キャンセル

0

CSV:Table を使って書いてみました。

require 'csv'
infile = 'sample.csv'
outfile = 'sample_r.csv'

table = CSV.table(infile)
table.map { |row| row[:average] = (row[:score01] + row[:score02]) / 2.0 }
File.write(outfile, table)

実行結果:
sample_r.csv

name,score01,score02,average
A,40,69,54.5
B,19,18,18.5
C,20,12,16.0
D,70,41,55.5
E,77,78,77.5

参考情報:

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.47%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Ruby

    7943questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。