类 CSV::Table

CSV::Table

CSV::Table 实例表示 CSV 数据。(参见 类 CSV)。

实例可能具有

实例方法

CSV::Table 有三组实例方法

创建 CSV::Table 实例

通常,通过使用标题解析 CSV 源来创建新的 CSV::Table 实例

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.class # => CSV::Table

你还可以直接创建一个实例。请参阅 ::new

标题

如果一个表有标题,则标题用作数据列的标签。每个标题用作其列的标签。

CSV::Table 对象的标题存储为字符串数组。

通常,标题在 CSV 源的第一行中定义

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.headers # => ["Name", "Value"]

如果没有定义标题,则数组为空

table = CSV::Table.new([])
table.headers # => []

访问模式

CSV::Table 提供了三种访问表数据的方式

CSV::Table 实例的访问模式影响其某些实例方法的行为

行模式

使用 by_row! 方法将 Set 表设置为行模式

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.by_row! # => #<CSV::Table mode:row row_count:4>

通过整数索引指定单行

# Get a row.
table[1] # => #<CSV::Row "Name":"bar" "Value":"1">
# Set a row, then get it.
table[1] = CSV::Row.new(['Name', 'Value'], ['bam', 3])
table[1] # => #<CSV::Row "Name":"bam" "Value":3>

通过范围指定一系列行

# Get rows.
table[1..2] # => [#<CSV::Row "Name":"bam" "Value":3>, #<CSV::Row "Name":"baz" "Value":"2">]
# Set rows, then get them.
table[1..2] = [
  CSV::Row.new(['Name', 'Value'], ['bat', 4]),
  CSV::Row.new(['Name', 'Value'], ['bad', 5]),
]
table[1..2] # => [["Name", #<CSV::Row "Name":"bat" "Value":4>], ["Value", #<CSV::Row "Name":"bad" "Value":5>]]

列模式

Set 使用方法 by_col! 将表格设置为列模式

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.by_col! # => #<CSV::Table mode:col row_count:4>

通过整数索引指定列

# Get a column.
table[0]
# Set a column, then get it.
table[0] = ['FOO', 'BAR', 'BAZ']
table[0] # => ["FOO", "BAR", "BAZ"]

通过字符串标题指定列

# Get a column.
table['Name'] # => ["FOO", "BAR", "BAZ"]
# Set a column, then get it.
table['Name'] = ['Foo', 'Bar', 'Baz']
table['Name'] # => ["Foo", "Bar", "Baz"]

混合模式

在混合模式中,您可以引用行或列

Set 使用方法 by_col_or_row! 将表格设置为混合模式

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.by_col_or_row! # => #<CSV::Table mode:col_or_row row_count:4>

通过整数索引指定单行

# Get a row.
table[1] # => #<CSV::Row "Name":"bar" "Value":"1">
# Set a row, then get it.
table[1] = CSV::Row.new(['Name', 'Value'], ['bam', 3])
table[1] # => #<CSV::Row "Name":"bam" "Value":3>

通过范围指定一系列行

# Get rows.
table[1..2] # => [#<CSV::Row "Name":"bam" "Value":3>, #<CSV::Row "Name":"baz" "Value":"2">]
# Set rows, then get them.
table[1] = CSV::Row.new(['Name', 'Value'], ['bat', 4])
table[2] = CSV::Row.new(['Name', 'Value'], ['bad', 5])
table[1..2] # => [["Name", #<CSV::Row "Name":"bat" "Value":4>], ["Value", #<CSV::Row "Name":"bad" "Value":5>]]

通过字符串标题指定列

# Get a column.
table['Name'] # => ["foo", "bat", "bad"]
# Set a column, then get it.
table['Name'] = ['Foo', 'Bar', 'Baz']
table['Name'] # => ["Foo", "Bar", "Baz"]

属性

mode[R]

当前访问模式,用于索引和迭代。

table[R]

用于比较相等性的内部数据格式。

公共类方法

CSV::Table.new(array_of_rows, headers = nil) → csv_table 单击以切换源

返回新的 CSV::Table 对象。

  • 参数 array_of_rows 必须是 CSV::Row 对象的数组。

  • 如果给定参数 headers,它可以是字符串数组。


创建一个空的 CSV::Table 对象

table = CSV::Table.new([])
table # => #<CSV::Table mode:col_or_row row_count:1>

创建一个非空的 CSV::Table 对象

rows = [
  CSV::Row.new([], []),
  CSV::Row.new([], []),
  CSV::Row.new([], []),
]
table  = CSV::Table.new(rows)
table # => #<CSV::Table mode:col_or_row row_count:4>

如果参数 headers 是字符串数组,则这些字符串将成为表格的标题

table = CSV::Table.new([], headers: ['Name', 'Age'])
table.headers # => ["Name", "Age"]

如果未给定参数 headers 并且表格有行,则标题将取自第一行

rows = [
  CSV::Row.new(['Foo', 'Bar'], []),
  CSV::Row.new(['foo', 'bar'], []),
  CSV::Row.new(['FOO', 'BAR'], []),
]
table  = CSV::Table.new(rows)
table.headers # => ["Foo", "Bar"]

如果未给定参数 headers 并且表格为空(没有行),则标题也为空

table  = CSV::Table.new([])
table.headers # => []

如果参数 array_of_rows 不是数组对象,则引发异常

# Raises NoMethodError (undefined method `first' for :foo:Symbol):
CSV::Table.new(:foo)

如果 array_of_rows 的元素不是 CSV::Table 对象,则引发异常

# Raises NoMethodError (undefined method `headers' for :foo:Symbol):
CSV::Table.new([:foo])
# File lib/csv/table.rb, line 199
def initialize(array_of_rows, headers: nil)
  @table = array_of_rows
  @headers = headers
  unless @headers
    if @table.empty?
      @headers = []
    else
      @headers = @table.first.headers
    end
  end

  @mode  = :col_or_row
end

公共实例方法

table << row_or_array → self 单击以切换源

如果 row_or_array 是 CSV::Row 对象,则将其追加到表格中

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table << CSV::Row.new(table.headers, ['bat', 3])
table[3] # => #<CSV::Row "Name":"bat" "Value":3>

如果 row_or_array 是数组,则使用它创建一个新的 CSV::Row 对象,然后将其追加到表格中

table << ['bam', 4]
table[4] # => #<CSV::Row "Name":"bam" "Value":4>
# File lib/csv/table.rb, line 762
def <<(row_or_array)
  if row_or_array.is_a? Array  # append Array
    @table << Row.new(headers, row_or_array)
  else                         # append Row
    @table << row_or_array
  end

  self # for chaining
end
table == other_table → true or false 单击以切换源

如果 self 的每一行都 == other_table 的对应行,则返回 true,否则返回 false

访问模式不会影响结果。

相等表格

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
other_table = CSV.parse(source, headers: true)
table == other_table # => true

行数不同

other_table.delete(2)
table == other_table # => false

最后一行不同

other_table << ['bat', 3]
table == other_table # => false
# File lib/csv/table.rb, line 965
def ==(other)
  return @table == other.table if other.is_a? CSV::Table
  @table == other
end
table[n] → 行或列数据 单击切换源
table[range] → 行数组或列数据数组
table[header] → 列数据数组

从表中返回数据;不修改表。


按整数索引获取行
  • 格式:table[n]n 为整数。

  • 访问模式::row:col_or_row

  • 返回值:表的第 n 行(如果该行存在);否则为 nil

如果该行存在,则返回表的第 n

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.by_row! # => #<CSV::Table mode:row row_count:4>
table[1] # => #<CSV::Row "Name":"bar" "Value":"1">
table.by_col_or_row! # => #<CSV::Table mode:col_or_row row_count:4>
table[1] # => #<CSV::Row "Name":"bar" "Value":"1">

如果 n 为负数,则从最后一行开始向后计数

table[-1] # => #<CSV::Row "Name":"baz" "Value":"2">

如果 n 过大或过小,则返回 nil

table[4] # => nil
table[-4] # => nil

如果访问模式为 :rown 不是整数,则引发异常

table.by_row! # => #<CSV::Table mode:row row_count:4>
# Raises TypeError (no implicit conversion of String into Integer):
table['Name']

按整数索引获取列
  • 格式:table[n]n 为整数。

  • 访问模式::col

  • 返回值:表的第 n 列(如果该列存在);否则为长度为 self.sizenil 字段数组。

如果该列存在,则返回表的第 n

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.by_col! # => #<CSV::Table mode:col row_count:4>
table[1] # => ["0", "1", "2"]

如果 n 为负数,则从最后一列开始向后计数

table[-2] # => ["foo", "bar", "baz"]

如果 n 过大或过小,则返回 nil 字段数组

table[4] # => [nil, nil, nil]
table[-4] # => [nil, nil, nil]

按范围获取行
  • 格式:table[range]range 为范围对象。

  • 访问模式::row:col_or_row

  • 返回值:从行 range.start 开始的表行(如果这些行存在)。

从行 range.first 开始返回表行(如果这些行存在)

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.by_row! # => #<CSV::Table mode:row row_count:4>
rows = table[1..2] # => #<CSV::Row "Name":"bar" "Value":"1">
rows # => [#<CSV::Row "Name":"bar" "Value":"1">, #<CSV::Row "Name":"baz" "Value":"2">]
table.by_col_or_row! # => #<CSV::Table mode:col_or_row row_count:4>
rows = table[1..2] # => #<CSV::Row "Name":"bar" "Value":"1">
rows # => [#<CSV::Row "Name":"bar" "Value":"1">, #<CSV::Row "Name":"baz" "Value":"2">]

如果行太少,则从 range.start 到末尾返回所有行

rows = table[1..50] # => #<CSV::Row "Name":"bar" "Value":"1">
rows # => [#<CSV::Row "Name":"bar" "Value":"1">, #<CSV::Row "Name":"baz" "Value":"2">]

特殊情况:如果 range.start == table.size,则返回一个空数组

table[table.size..50] # => []

如果 range.end 为负数,则从末尾计算结束索引

rows = table[0..-1]
rows # => [#<CSV::Row "Name":"foo" "Value":"0">, #<CSV::Row "Name":"bar" "Value":"1">, #<CSV::Row "Name":"baz" "Value":"2">]

如果 range.start 为负数,则从末尾计算开始索引

rows = table[-1..2]
rows # => [#<CSV::Row "Name":"baz" "Value":"2">]

如果 range.start 大于 table.size,则返回 nil

table[4..4] # => nil

按范围获取列
  • 格式:table[range]range 为范围对象。

  • 访问模式::col

  • 返回值:从列 range.start 开始的表列数据(如果这些列存在)。

如果列存在,则返回表中的列值;这些值按行排列

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.by_col!
table[0..1] # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

特殊情况:如果 range.start == headers.size,则返回一个由空数组组成的数组(大小:table.size

table[table.headers.size..50] # => [[], [], []]

如果 range.end 为负数,则从末尾计算结束索引

table[0..-1] # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

如果 range.start 为负数,则从末尾计算开始索引

table[-2..2] # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]

如果 range.start 大于 table.size,则返回一个由 nil 值组成的数组

table[4..4] # => [nil, nil, nil]

按其字符串标题获取列
  • 形式:table[header]header 是字符串标题。

  • 访问模式::col:col_or_row

  • 返回值:如果该 header 存在,则返回表中的列数据。

如果列存在,则返回表中的列值

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.by_col! # => #<CSV::Table mode:col row_count:4>
table['Name'] # => ["foo", "bar", "baz"]
table.by_col_or_row! # => #<CSV::Table mode:col_or_row row_count:4>
col = table['Name']
col # => ["foo", "bar", "baz"]

修改返回的列值不会修改表

col[0] = 'bat'
col # => ["bat", "bar", "baz"]
table['Name'] # => ["foo", "bar", "baz"]

如果没有该列,则返回一个由 nil 值组成的数组

table['Nosuch'] # => [nil, nil, nil]
# File lib/csv/table.rb, line 514
def [](index_or_header)
  if @mode == :row or  # by index
     (@mode == :col_or_row and (index_or_header.is_a?(Integer) or index_or_header.is_a?(Range)))
    @table[index_or_header]
  else                 # by header
    @table.map { |row| row[index_or_header] }
  end
end
table[n] = row → row 单击以切换源
table[n] = field_or_array_of_fields → field_or_array_of_fields
table[header] = field_or_array_of_fields → field_or_array_of_fields

将数据放入表中。


Set 按其整数索引设置行
  • 形式:table[n] = rown 为整数,row 为 CSV::Row 实例或字段数组。

  • 访问模式::row:col_or_row

  • 返回值:row

如果行存在,则替换它

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
new_row = CSV::Row.new(['Name', 'Value'], ['bat', 3])
table.by_row! # => #<CSV::Table mode:row row_count:4>
return_value = table[0] = new_row
return_value.equal?(new_row) # => true # Returned the row
table[0].to_h # => {"Name"=>"bat", "Value"=>3}

访问模式为 :col_or_row

table.by_col_or_row! # => #<CSV::Table mode:col_or_row row_count:4>
table[0] = CSV::Row.new(['Name', 'Value'], ['bam', 4])
table[0].to_h # => {"Name"=>"bam", "Value"=>4}

使用数组而不是 CSV::Row,从表中继承标题

array = ['bad', 5]
return_value = table[0] = array
return_value.equal?(array) # => true # Returned the array
table[0].to_h # => {"Name"=>"bad", "Value"=>5}

如果行不存在,则通过添加行来扩展表:根据需要分配具有 nil 的行

table.size # => 3
table[5] = ['bag', 6]
table.size # => 6
table[3] # => nil
table[4]# => nil
table[5].to_h # => {"Name"=>"bag", "Value"=>6}

请注意,nil 行实际上是 nil,而不是 nil 字段的行。


Set 按其整数索引设置列
  • 形式:table[n] = array_of_fieldsn 为整数,array_of_fields 为字符串字段数组。

  • 访问模式::col

  • 返回值:array_of_fields

如果列存在,则替换它

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
new_col = [3, 4, 5]
table.by_col! # => #<CSV::Table mode:col row_count:4>
return_value = table[1] = new_col
return_value.equal?(new_col) # => true # Returned the column
table[1] # => [3, 4, 5]
# The rows, as revised:
table.by_row! # => #<CSV::Table mode:row row_count:4>
table[0].to_h # => {"Name"=>"foo", "Value"=>3}
table[1].to_h # => {"Name"=>"bar", "Value"=>4}
table[2].to_h # => {"Name"=>"baz", "Value"=>5}
table.by_col! # => #<CSV::Table mode:col row_count:4>

如果值太少,则用 nil 值填充

table[1] = [0]
table[1] # => [0, nil, nil]

如果值太多,则忽略多余的值

table[1] = [0, 1, 2, 3, 4]
table[1] # => [0, 1, 2]

如果给定单个值,则用该值替换列中的所有字段

table[1] = 'bat'
table[1] # => ["bat", "bat", "bat"]

Set 按其字符串标题设置列
  • 形式:table[header] = field_or_array_of_fieldsheader 为字符串标题,field_or_array_of_fields 为字段值或字符串字段数组。

  • 访问模式::col:col_or_row

  • 返回值:field_or_array_of_fields

如果列存在,则替换它

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
new_col = [3, 4, 5]
table.by_col! # => #<CSV::Table mode:col row_count:4>
return_value = table['Value'] = new_col
return_value.equal?(new_col) # => true # Returned the column
table['Value'] # => [3, 4, 5]
# The rows, as revised:
table.by_row! # => #<CSV::Table mode:row row_count:4>
table[0].to_h # => {"Name"=>"foo", "Value"=>3}
table[1].to_h # => {"Name"=>"bar", "Value"=>4}
table[2].to_h # => {"Name"=>"baz", "Value"=>5}
table.by_col! # => #<CSV::Table mode:col row_count:4>

如果值太少,则用 nil 值填充

table['Value'] = [0]
table['Value'] # => [0, nil, nil]

如果值太多,则忽略多余的值

table['Value'] = [0, 1, 2, 3, 4]
table['Value'] # => [0, 1, 2]

如果列不存在,则通过添加列来扩展表

table['Note'] = ['x', 'y', 'z']
table['Note'] # => ["x", "y", "z"]
# The rows, as revised:
table.by_row!
table[0].to_h # => {"Name"=>"foo", "Value"=>0, "Note"=>"x"}
table[1].to_h # => {"Name"=>"bar", "Value"=>1, "Note"=>"y"}
table[2].to_h # => {"Name"=>"baz", "Value"=>2, "Note"=>"z"}
table.by_col!

如果给定单个值,则用该值替换列中的所有字段

table['Value'] = 'bat'
table['Value'] # => ["bat", "bat", "bat"]
# File lib/csv/table.rb, line 649
def []=(index_or_header, value)
  if @mode == :row or  # by index
     (@mode == :col_or_row and index_or_header.is_a? Integer)
    if value.is_a? Array
      @table[index_or_header] = Row.new(headers, value)
    else
      @table[index_or_header] = value
    end
  else                 # set column
    unless index_or_header.is_a? Integer
      index = @headers.index(index_or_header) || @headers.size
      @headers[index] = index_or_header
    end
    if value.is_a? Array  # multiple values
      @table.each_with_index do |row, i|
        if row.header_row?
          row[index_or_header] = index_or_header
        else
          row[index_or_header] = value[i]
        end
      end
    else                  # repeated value
      @table.each do |row|
        if row.header_row?
          row[index_or_header] = index_or_header
        else
          row[index_or_header] = value
        end
      end
    end
  end
end
by_col → table_dup 单击以切换源

返回 self 的副本,采用列模式(请参阅 列模式

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.mode # => :col_or_row
dup_table = table.by_col
dup_table.mode # => :col
dup_table.equal?(table) # => false # It's a dup

这可以用来链接方法调用而不更改模式(但也会影响性能和内存使用情况)

dup_table.by_col['Name']

还要注意,对副本表进行的更改不会影响原表。

# File lib/csv/table.rb, line 242
def by_col
  self.class.new(@table.dup).by_col!
end
by_col! → self 单击以切换源

self 的模式设置为列模式(请参阅 列模式);返回 self

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.mode # => :col_or_row
table1 = table.by_col!
table.mode # => :col
table1.equal?(table) # => true # Returned self
# File lib/csv/table.rb, line 257
def by_col!
  @mode = :col

  self
end
by_col_or_row → table_dup 单击以切换源

以混合模式返回 self 的副本(请参阅 混合模式

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true).by_col!
table.mode # => :col
dup_table = table.by_col_or_row
dup_table.mode # => :col_or_row
dup_table.equal?(table) # => false # It's a dup

这可以用来链接方法调用而不更改模式(但也会影响性能和内存使用情况)

dup_table.by_col_or_row['Name']

还要注意,对副本表进行的更改不会影响原表。

# File lib/csv/table.rb, line 280
def by_col_or_row
  self.class.new(@table.dup).by_col_or_row!
end
by_col_or_row! → self 单击以切换源

self 的模式设置为混合模式(请参阅 混合模式);返回 self

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true).by_col!
table.mode # => :col
table1 = table.by_col_or_row!
table.mode # => :col_or_row
table1.equal?(table) # => true # Returned self
# File lib/csv/table.rb, line 295
def by_col_or_row!
  @mode = :col_or_row

  self
end
by_row → table_dup 单击以切换源

以行模式返回 self 的副本(请参阅 行模式

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.mode # => :col_or_row
dup_table = table.by_row
dup_table.mode # => :row
dup_table.equal?(table) # => false # It's a dup

这可以用来链接方法调用而不更改模式(但也会影响性能和内存使用情况)

dup_table.by_row[1]

还要注意,对副本表进行的更改不会影响原表。

# File lib/csv/table.rb, line 318
def by_row
  self.class.new(@table.dup).by_row!
end
by_row! → self 单击以切换源

self 的模式设置为行模式(请参阅 行模式);返回 self

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.mode # => :col_or_row
table1 = table.by_row!
table.mode # => :row
table1.equal?(table) # => true # Returned self
# File lib/csv/table.rb, line 333
def by_row!
  @mode = :row

  self
end
delete(*indexes) → deleted_values 单击以切换源
delete(*headers) → deleted_values

如果访问模式为 :row:col_or_row,并且每个参数都是整数或范围,则返回已删除的行。否则,返回已删除的列数据。

在任何一种情况下,返回的值都按参数指定的顺序排列。参数可以重复。


将行作为 CSV::Row 对象的数组返回。

一个索引

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
deleted_values = table.delete(0)
deleted_values # => [#<CSV::Row "Name":"foo" "Value":"0">]

两个索引

table = CSV.parse(source, headers: true)
deleted_values = table.delete(2, 0)
deleted_values # => [#<CSV::Row "Name":"baz" "Value":"2">, #<CSV::Row "Name":"foo" "Value":"0">]

将列数据作为列数组返回。

一个标题

table = CSV.parse(source, headers: true)
deleted_values = table.delete('Name')
deleted_values # => ["foo", "bar", "baz"]

两个标题

table = CSV.parse(source, headers: true)
deleted_values = table.delete('Value', 'Name')
deleted_values # => [["0", "1", "2"], ["foo", "bar", "baz"]]
# File lib/csv/table.rb, line 834
def delete(*indexes_or_headers)
  if indexes_or_headers.empty?
    raise ArgumentError, "wrong number of arguments (given 0, expected 1+)"
  end
  deleted_values = indexes_or_headers.map do |index_or_header|
    if @mode == :row or  # by index
        (@mode == :col_or_row and index_or_header.is_a? Integer)
      @table.delete_at(index_or_header)
    else                 # by header
      if index_or_header.is_a? Integer
        @headers.delete_at(index_or_header)
      else
        @headers.delete(index_or_header)
      end
      @table.map { |row| row.delete(index_or_header).last }
    end
  end
  if indexes_or_headers.size == 1
    deleted_values[0]
  else
    deleted_values
  end
end
delete_if {|row_or_column| ... } → self 单击以切换源

删除块返回真值的行或列;返回 self

在访问模式为 :row:col_or_row 时删除行;使用每个 CSV::Row 对象调用块

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.by_row! # => #<CSV::Table mode:row row_count:4>
table.size # => 3
table.delete_if {|row| row['Name'].start_with?('b') }
table.size # => 1

当访问模式为 :col 时,移除列;使用每个列作为包含标题和列字段数组的 2 元素数组,调用块

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.by_col! # => #<CSV::Table mode:col row_count:4>
table.headers.size # => 2
table.delete_if {|column_data| column_data[1].include?('2') }
table.headers.size # => 1

如果没有提供块,则返回一个新的枚举器

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.delete_if # => #<Enumerator: #<CSV::Table mode:col_or_row row_count:4>:delete_if>
# File lib/csv/table.rb, line 887
def delete_if(&block)
  return enum_for(__method__) { @mode == :row or @mode == :col_or_row ? size : headers.size } unless block_given?

  if @mode == :row or @mode == :col_or_row  # by index
    @table.delete_if(&block)
  else                                      # by header
    headers.each do |header|
      delete(header) if yield([header, self[header]])
    end
  end

  self # for chaining
end
dig(index_or_header, *index_or_headers) 点击以切换源

通过在每一步调用 dig 提取由 indexheader 对象序列指定嵌套值,如果任何中间步骤为 nil,则返回 nil。

# File lib/csv/table.rb, line 1021
def dig(index_or_header, *index_or_headers)
  value = self[index_or_header]
  if value.nil?
    nil
  elsif index_or_headers.empty?
    value
  else
    unless value.respond_to?(:dig)
      raise TypeError, "#{value.class} does not have \#dig method"
    end
    value.dig(*index_or_headers)
  end
end
each {|row_or_column| ... ) → self 点击以切换源

使用每个行或列调用块;返回 self

当访问模式为 :row:col_or_row 时,使用每个 CSV::Row 对象调用块

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.by_row! # => #<CSV::Table mode:row row_count:4>
table.each {|row| p row }

输出

#<CSV::Row "Name":"foo" "Value":"0">
#<CSV::Row "Name":"bar" "Value":"1">
#<CSV::Row "Name":"baz" "Value":"2">

当访问模式为 :col 时,使用每个列作为包含标题和列字段数组的 2 元素数组,调用块

table.by_col! # => #<CSV::Table mode:col row_count:4>
table.each {|column_data| p column_data }

输出

["Name", ["foo", "bar", "baz"]]
["Value", ["0", "1", "2"]]

如果没有提供块,则返回一个新的枚举器

table.each # => #<Enumerator: #<CSV::Table mode:col row_count:4>:each>
# File lib/csv/table.rb, line 930
def each(&block)
  return enum_for(__method__) { @mode == :col ? headers.size : size } unless block_given?

  if @mode == :col
    headers.each.with_index do |header, i|
      yield([header, @table.map {|row| row[header, i]}])
    end
  else
    @table.each(&block)
  end

  self # for chaining
end
headers → array_of_headers 点击以切换源

返回一个包含表格的字符串标题的新数组。

如果表格不为空,则返回第一行的标题

rows = [
  CSV::Row.new(['Foo', 'Bar'], []),
  CSV::Row.new(['FOO', 'BAR'], []),
  CSV::Row.new(['foo', 'bar'], []),
]
table  = CSV::Table.new(rows)
table.headers # => ["Foo", "Bar"]
table.delete(0)
table.headers # => ["FOO", "BAR"]
table.delete(0)
table.headers # => ["foo", "bar"]

如果表格为空,则返回表格本身中标题的副本

table.delete(0)
table.headers # => ["Foo", "Bar"]
# File lib/csv/table.rb, line 360
def headers
  if @table.empty?
    @headers.dup
  else
    @table.first.headers
  end
end
inspect → string 点击以切换源

返回显示表格的 US-ASCII 编码字符串

  • 类:CSV::Table

  • 访问模式::row:col:col_or_row

  • 大小:Row 计数,包括标题行。

示例

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.inspect # => "#<CSV::Table mode:col_or_row row_count:4>\nName,Value\nfoo,0\nbar,1\nbaz,2\n"
# File lib/csv/table.rb, line 1048
def inspect
  inspected = +"#<#{self.class} mode:#{@mode} row_count:#{to_a.size}>"
  summary = to_csv(limit: 5)
  inspected << "\n" << summary if summary.encoding.ascii_compatible?
  inspected
end
push(*rows_or_arrays) → self 点击以切换源

附加多行的快捷方式。等效于

rows.each {|row| self << row }

每个参数可以是 CSV::Row 对象或数组

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
rows = [
  CSV::Row.new(table.headers, ['bat', 3]),
  ['bam', 4]
]
table.push(*rows)
table[3..4] # => [#<CSV::Row "Name":"bat" "Value":3>, #<CSV::Row "Name":"bam" "Value":4>]
# File lib/csv/table.rb, line 788
def push(*rows)
  rows.each { |row| self << row }

  self # for chaining
end
to_a → array_of_arrays 点击以切换源

将表格作为数组的数组返回;标题在第一行

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.to_a # => [["Name", "Value"], ["foo", "0"], ["bar", "1"], ["baz", "2"]]
# File lib/csv/table.rb, line 978
def to_a
  array = [headers]
  @table.each do |row|
    array.push(row.fields) unless row.header_row?
  end

  array
end
to_csv(**options) → csv_string 点击以切换源

将表格作为 CSV 字符串返回。请参阅生成选项

将选项 write_headers 的默认值设为 true

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.to_csv # => "Name,Value\nfoo,0\nbar,1\nbaz,2\n"

如果选项 write_headers 给定为 false,则省略标题(参见 {Option write_headers}

table.to_csv(write_headers: false) # => "foo,0\nbar,1\nbaz,2\n"

如果选项 limit 给定为 2,则限制行数

table.to_csv(limit: 2) # => "Name,Value\nfoo,0\nbar,1\n"
# File lib/csv/table.rb, line 1004
def to_csv(write_headers: true, limit: nil, **options)
  array = write_headers ? [headers.to_csv(**options)] : []
  limit ||= @table.size
  limit = @table.size + 1 + limit if limit < 0
  limit = 0 if limit < 0
  @table.first(limit).each do |row|
    array.push(row.fields.to_csv(**options)) unless row.header_row?
  end

  array.join("")
end
别名: to_s
to_s
别名: to_csv
values_at(*indexes) → array_of_rows 单击以切换源
values_at(*headers) → array_of_columns_data

如果访问模式为 :row:col_or_row,且每个参数都是整数或范围,则返回行。否则,返回列数据。

在任何一种情况下,返回的值都按参数指定的顺序排列。参数可以重复。


将行作为 CSV::Row 对象的数组返回。

无参数

source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(source, headers: true)
table.values_at # => []

一个索引

values = table.values_at(0)
values # => [#<CSV::Row "Name":"foo" "Value":"0">]

两个索引

values = table.values_at(2, 0)
values # => [#<CSV::Row "Name":"baz" "Value":"2">, #<CSV::Row "Name":"foo" "Value":"0">]

一个范围

values = table.values_at(1..2)
values # => [#<CSV::Row "Name":"bar" "Value":"1">, #<CSV::Row "Name":"baz" "Value":"2">]

范围和索引

values = table.values_at(0..1, 1..2, 0, 2)
pp values

输出

[#<CSV::Row "Name":"foo" "Value":"0">,
 #<CSV::Row "Name":"bar" "Value":"1">,
 #<CSV::Row "Name":"bar" "Value":"1">,
 #<CSV::Row "Name":"baz" "Value":"2">,
 #<CSV::Row "Name":"foo" "Value":"0">,
 #<CSV::Row "Name":"baz" "Value":"2">]

将列数据作为行数组返回,每个数组都包含该行的指定列数据

values = table.values_at('Name')
values # => [["foo"], ["bar"], ["baz"]]
values = table.values_at('Value', 'Name')
values # => [["0", "foo"], ["1", "bar"], ["2", "baz"]]
# File lib/csv/table.rb, line 734
def values_at(*indices_or_headers)
  if @mode == :row or  # by indices
     ( @mode == :col_or_row and indices_or_headers.all? do |index|
                                  index.is_a?(Integer)         or
                                  ( index.is_a?(Range)         and
                                    index.first.is_a?(Integer) and
                                    index.last.is_a?(Integer) )
                                end )
    @table.values_at(*indices_or_headers)
  else                 # by headers
    @table.map { |row| row.values_at(*indices_or_headers) }
  end
end