【问题标题】:Write a JSON file for Array of Arrays为数组数组编写一个 JSON 文件
【发布时间】:2014-07-07 15:30:59
【问题描述】:

我有几个 nx3 数组要用 JSON 编写,以便可以在 Ruby 中进一步读取。

到目前为止,我已完成代码,但JSON.parse 在将第二个数组写入文件时返回错误。如何编写 JSON 以便可以单独读取每个数组?

这里是代码和写好的 JSON 文件。

require 'json'
wp = []
wp[0]=[704/4,1124/4,0]
wp[1]=[704/4,1608/4,0]
wp[2]=[942/4,1608/4,0]



a = wp.map{|wp|{x: wp[0].to_i, y:wp[1].to_i, z:wp[2].to_i}}

wp2 = []
wp2[0]=[7055/4,1124/4,0]
wp2[1]=[704/4,1608/4,0]
wp2[2]=[942/4,1608/4,0]
wp2[3]=[942/4,2107/4,0]

a2 = wp2.map{|wp2|{x: wp2[0].to_i, y:wp2[1].to_i, z:wp2[2].to_i}}



File.open(".../temp.json","w") do |f|
  f.write(a.to_json)
end


File.open(".../temp.json","a+") do |f|
  f.write(a2.to_json)
end

f = open(".../temp.json")
jon  = f.read
#This completes teh writing

psd = JSON.parse(jon)


psd.each do |xo|
  print xo["y"].to_i,"\n"
end

当文件中只有一个数组被写入时,它会被正确读取,但当第二个数组被写入时,它会正确写入,但会出错:

(JSON::ParserError)
    from /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/json/common.rb:155:in `parse'
    from jsont.rb:35:in `<main>'
"The JSON.parse(jon) gives Error."


[{"x":176,"y":281,"z":0},{"x":176,"y":402,"z":0},{"x":235,"y":402,"z":0},{"x":235,"y":526,"z":0},{"x":322,"y":526,"z":0},{"x":448,"y":526,"z":0},{"x":508,"y":526,"z":0},{"x":508,"y":640,"z":0},{"x":577,"y":640,"z":0},{"x":577,"y":669,"z":0},{"x":718,"y":669,"z":0}][{"x":1763,"y":281,"z":0},{"x":176,"y":402,"z":0},{"x":235,"y":402,"z":0},{"x":235,"y":526,"z":0},{"x":322,"y":526,"z":0},{"x":448,"y":526,"z":0},{"x":508,"y":526,"z":0},{"x":508,"y":640,"z":0},{"x":577,"y":640,"z":0},{"x":577,"y":669,"z":0},{"x":718,"y":669,"z":0}]

您会注意到,在 JSON 文件中,两个数组已连接在一起。我知道这是导致错误的原因。但是我该如何纠正它,以便我能够以二维数组的形式访问每个坐标?不知道之前要写多少个数组。

【问题讨论】:

  • 当您提出问题时,将您的代码和数据减少到演示/重​​现问题所需的最低限度。除此之外的任何事情都只会妨碍人们为您提供帮助。

标签: ruby arrays json


【解决方案1】:

JSON 中的正确数组(偶数数组)以 [ 开头,以 ] 结尾,每两个项目之间有一个 ,

因此,以下不是有效的 JSON:

[1, 2, 3][4, 5, 6]

虽然这是:

[[1, 2, 3], [4, 5, 6]]

为了解决你的问题,你可以将每个数组写在一个新行中,然后当你读回它们时,你可以逐行读取它们,分别解析:

File.open(".../temp.json","w") do |f|
  f.puts(a.to_json)
end


File.open(".../temp.json","a+") do |f|
  f.puts(a2.to_json)
end

这将创建一个如下所示的文件:

[{"x":176,"y":281,"z":0},{"x":176,"y":402,"z":0},{"x":235,"y":402,"z":0},{"x":235,"y":526,"z":0},{"x":322,"y":526,"z":0},{"x":448,"y":526,"z":0},{"x":508,"y":526,"z":0},{"x":508,"y":640,"z":0},{"x":577,"y":640,"z":0},{"x":577,"y":669,"z":0},{"x":718,"y":669,"z":0}]
[{"x":1763,"y":281,"z":0},{"x":176,"y":402,"z":0},{"x":235,"y":402,"z":0},{"x":235,"y":526,"z":0},{"x":322,"y":526,"z":0},{"x":448,"y":526,"z":0},{"x":508,"y":526,"z":0},{"x":508,"y":640,"z":0},{"x":577,"y":640,"z":0},{"x":577,"y":669,"z":0},{"x":718,"y":669,"z":0}]

您以后可以这样阅读:

arrs = File.readlines(".../temp.json").map do |line|
  JSON.parse(line)
end

这应该产生一个数组数组。

【讨论】:

  • 简短而简单。工作。谢谢!
【解决方案2】:

您正在将一堆连续的 JSON 字符串写入一个没有分隔符的文件。

您的选择是:

  1. 创建一个包含所有数组的数组,将其转换为 JSON 并将其写入您的文件中
  2. 用分隔符分隔 JSON 字符串,然后在读取时拆分它们。使用换行符可能最容易做到这一点(即将f.write 更改为f.puts,然后在读取时遍历每一行并一次解析每一行)。

【讨论】:

    【解决方案3】:

    也许这会帮助你学习如何钓鱼......

    您不能将 JSON 输出写为两个单独的简单写入,并期望解析器能够正确解释数据。 JSON,无论是美化并写成多行,还是写成单行的流,仍然是一个对象,要么是数组,要么是散列。两者都必须有它们的包装 [...]{...} 和一个显示有更多元素 ',' 的延续字符,这两者都是你所缺少的重新写入数据。

    考虑这段代码及其输出:

    require 'json'
    
    a_of_h_1 = [{'a' => 1}, {'b' => 2}]
    a_of_h_2 = [{'c' => 3}, {'d' => 4}]
    
    File.open('foo', 'w') do |fo|
      fo.puts JSON[a_of_h_1]
      fo.puts JSON[a_of_h_2]
    end
    

    查看 shell 中的文件如下所示:

    [{"a":1},{"b":2}]
    [{"c":3},{"d":4}]
    

    如果我尝试读取该文件:

    JSON[File.read('foo')]
    

    我明白了:

    unexpected token at '[{"c":3},{"d":4}] (JSON::ParserError)
    

    这是因为没有包含/包装的分隔符集告诉解析器数据是单个对象的一部分,并且没有中间 ',' 告诉解析器还有其他数据。我可以编写与哈希数组相同的数据:

    File.open('foo', 'w') do |fo|
      fo.puts JSON[[a_of_h_1, a_of_h_2]]
    end
    

    这导致文件看起来像:

    [[{"a":1},{"b":2}],[{"c":3},{"d":4}]]
    

    注意包含[...] 和分隔','

    现在解析器很高兴并且能够正确检索对象:

    (a_a1, a_a2) = JSON[File.read('foo')]
    a_a1 # => [{"a"=>1}, {"b"=>2}]
    a_a2 # => [{"c"=>3}, {"d"=>4}]
    

    好的,回到你的代码。让解析器为您生成流更容易/更安全/更好。如果您不能这样做,那么您必须了解解析器需要如何查看数据,然后以该格式创建文件,这并不难。

    再次,首先查看生成器对您的数据结构的简单版本的作用:

    puts JSON[[a_of_h_1, a_of_h_2]]
    # >> [[{"a":1},{"b":2}],[{"c":3},{"d":4}]]
    

    很容易弄清楚如何构建文件的格式。我强烈建议让生成器尽可能多地完成繁重的工作,所以我让它序列化各个子数组:

    a_of_a_of_h = []
    a_of_a_of_h << a_of_h_1
    a_of_a_of_h << a_of_h_2
    
    File.open('foo', 'w') do |fo|
      fo.puts '['
      a_of_a_of_h[0..-2].each do |a_of_h|
        fo.puts a_of_h.to_json
        fo.puts ','
      end
      fo.puts a_of_a_of_h[-1].to_json
      fo.puts ']'
    end
    

    该代码写入开头'[',写入所有子数组并添加',' 字符,然后重复到倒数第二个元素,然后写入最后一个元素和结尾']'。 现在文件看起来像:

    [
    [{"a":1},{"b":2}]
    ,
    [{"c":3},{"d":4}]
    ]
    

    它不漂亮,但它有效:

    JSON[File.read('foo')]
    # => [[{"a"=>1}, {"b"=>2}], [{"c"=>3}, {"d"=>4}]]
    

    如果我稍微清理一下代码,我会得到:

    File.open('foo', 'w') do |fo|
    fo.puts '['
    fo.puts a_of_a_of_h.map(&:to_json).join(',')
    fo.puts ']'
    end
    

    map(&amp;:to_json)to_json 方法应用于每个子数组,然后join(',') 在所有序列化元素之间适当地添加','。请务必注意,join 不会像简单算法那样在最后一个元素后添加逗号。

    查看文件:

    [
    [{"a":1},{"b":2}],[{"c":3},{"d":4}]
    ]
    

    读取和解析数据:

    JSON[File.read('foo')]
    # => [[{"a"=>1}, {"b"=>2}], [{"c"=>3}, {"d"=>4}]]
    

    此时很容易将传入的数据重新分配回变量:

    (ary_a, ary_b) = JSON[File.read('foo')]
    # => [[{"a"=>1}, {"b"=>2}], [{"c"=>3}, {"d"=>4}]]
    ary_a # => [{"a"=>1}, {"b"=>2}]
    ary_b # => [{"c"=>3}, {"d"=>4}]
    

    在我的真实代码中,我会这样写:

    File.open('foo', 'w') do |fo|
      fo.puts '[', fo.puts a_of_a_of_h.map(&:to_json).join(','), ']'
    end
    

    如果由于内存限制或要求而不得不遍历数组。否则,我会把它扔到 JSON 生成器上,让它慢慢咀嚼:

    File.write('foo', JSON[a_of_a_of_h])
    JSON[File.read('foo')]
    # => [[{"a"=>1}, {"b"=>2}], [{"c"=>3}, {"d"=>4}]]
    

    【讨论】:

    • 感谢您编辑问题以获得更好的可读性 :-) 但是,@Agassi 的回答简短易懂。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-26
    • 2018-09-01
    相关资源
    最近更新 更多