简体   繁体   中英

Ruby view csv data

I'm getting from csv file some data (also how to select first 20 in csv?), for example:

A B C
D E F

also method:

def common_uploader
    require 'csv'
    arr = CSV.read("/#{Rails.public_path}/uploads_prices/"+params[:file], {:encoding => "CP1251:UTF-8", :col_sep => ";", :row_sep => :auto, :headers => :none})  
    @csv = []
    @csv << arr
  end

so it is array of arrays... But how can i view it normaly in haml view? How can i view array of arrays? i tried something like (also in each file i have different count of columns): view:

= @csv.first.each do |a|
 = a[:1]

Help me please to view csv data.

There are several ways you can read a set number of records, and you need to pick which to use based on the anticipated size of your data source.

Starting with a CSV file:

A1,A2,A3
B1,B2,B3
C1,C2,C3
D1,D2,D3
E1,E2,E3
F1,F2,F3

The simplest ways to read a fixed number of records would be one of these:

require 'csv'

array = CSV.read('test.csv')[0, 2]

Which returns an array of two sub-arrays:

[
    [0] [
        [0] "A1",
        [1] "A2",
        [2] "A3"
    ],
    [1] [
        [0] "B1",
        [1] "B2",
        [2] "B3"
    ]
]

An alternate is:

File.new('test.csv').readlines[0, 2].map{ |l| CSV.parse(l).flatten }

Which returns the same result, an array of two sub-arrays:

[
    [0] [
        [0] "A1",
        [1] "A2",
        [2] "A3"
    ],
    [1] [
        [0] "B1",
        [1] "B2",
        [2] "B3"
    ]
]

Both of these are fine for small input files, but will have problems if you are reading a few lines from a big input file. They will force Ruby to read the entire file into memory and create an intermediate array before slicing off the number of records you want. Where I work it's nothing for us to get gigabyte file sizes, so grabbing a small section of those files would make Ruby and the system do an inordinate amount of work building the intermediate array then throwing it away.

You are better off to only read the minimum number of records needed. Sometimes lines need to be skipped before reading; This demonstrates that idea, along with handling EOFError if the input file's EOF is encountered unexpectedly:

File.open('test.csv') do |fi|
  array = []
  begin  
    5.times { fi.readline }    
    2.times.each{ array += CSV.parse(fi.readline) }    
  rescue EOFError    
  end    
end  

Replace 5 with the number of records to skip, and 2 with the number to read. For that example I deliberately read off the end of the file to show how to skip lines, read some and then handle the EOF situation cleanly.

The data looks like:

[
    [0] [
        [0] "F1",
        [1] "F2",
        [2] "F3"
    ]
]

Because I'm using File.open with a block, the file is closed automatically after the block exists, avoiding leaving an open filehandle hanging around.

The HAML output section of your question isn't well defined at all, but this is one way to output the data:

array = []
File.open('test.csv') do |fi|
  begin  
    0.times { fi.readline }    
    2.times.each{ array += CSV.parse(fi.readline) }    
  rescue EOFError    
  end    
end  

require 'haml'

engine = Haml::Engine.new(<<EOT)
%html
  %body
    %table
      - array.each do |r|
        %tr
          - r.each do |c|
            %td= c
EOT
puts engine.render(Object.new, :array => array)

Which results in this output of a simple HTML table:

<html>
  <body>
    <table>
      <tr>
        <td>A1</td>
        <td>A2</td>
        <td>A3</td>
      </tr>
      <tr>
        <td>B1</td>
        <td>B2</td>
        <td>B3</td>
      </tr>
    </table>
  </body>
</html>

EDIT:

and my test file: dl.dropbox.com/u/59666091/qnt_small.csv i want to see this 7 columns in browser (via haml view)

Using this as my test data:

a1,a2,a3,a4,a5,a6,a7
b1,b2,b3,b4,b5,b6,b7
c1,c2,c3,c4,c5,c6,c7
d1,d2,d3,d4,d5,d6,d7
e1,e2,e3,e4,e5,e6,e7

and this code:

require 'csv'

array = []
File.open('test.csv') do |fi|
  begin
    0.times { fi.readline }
    2.times.each{ array += CSV.parse(fi.readline) }
  rescue EOFError
  end
end

require 'haml'

engine = Haml::Engine.new(<<EOT)
%html
  %body
    %table
      - array.each do |r|
        %tr
          - r.each do |c|
            %td= c
EOT
puts engine.render(Object.new, :array => array)

I get this output:

<html>
  <body>
    <table>
      <tr>
        <td>a1</td>
        <td>a2</td>
        <td>a3</td>
        <td>a4</td>
        <td>a5</td>
        <td>a6</td>
        <td>a7</td>
      </tr>
      <tr>
        <td>b1</td>
        <td>b2</td>
        <td>b3</td>
        <td>b4</td>
        <td>b5</td>
        <td>b6</td>
        <td>b7</td>
      </tr>
    </table>
  </body>
</html>

I made a minor change to move array outside the File.open block, nothing else is different.

You can do sth like that:

arr = CSV.read("/data.csv", {:encoding => "CP1251:UTF-8", :col_sep => ",", :row_sep => :auto, :headers => :none})

i = 0
arr.each do |row|
  if i == 20
    break
  else
    i += 1
  end

  # do  sth
  puts row
end

But I think it's not a beautiful solution. Edit: I don't understand why you put a instance of CSV into array, you wouldn't get a each row of csv file into array

require 'csv'
def parser
  CSV.open('data.csv', 'r', ';') do |row|
  puts row
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM