【问题标题】:Converting comma separated file to nested objects json in jq将逗号分隔的文件转换为jq中的嵌套对象json
【发布时间】:2017-10-08 14:20:12
【问题描述】:

我有一个 CSV 文件,我想使用 jq 解析并获得一个嵌套 JSON。我最近开始使用 JQ,我真的很喜欢这个工具。我了解基本功能,但解析 csv 文件似乎有点困难,尤其是打印嵌套对象。

示例输入

基因、外显子、总碱基、外显子碱基、总碱基、外显子碱基分数 PIK3CA,PIK3CA_Exon10;chr1;1000;1500,PIK3CA_Exon13;chr1;1000;1500,PIK3CA_Exon14;chr1;1000;1500,1927879,12993042,0.15 NRAS,NRAS_Exon4;chr1;1000;1500,NRAS_Amp_369;chr1;1000;1500,NRAS_Amp_371;chr1;1000;1500,NRAS_Amp_374;chr1;1000;1500,NRAS_Amp_379;chr1;1000;1500,880.4111,1500,880.4111, >

表头及输入数据说明

第一列总是有一个值。第二列可以有多个外显子(1 个或多个)。您可以看到它在第 2 行有 3 个值,在第 3 行有 5 个值。外显子碱基总是排在倒数第二列,总碱基排在最后一列,外显子碱基分数排在最后一列。

注意

我已添加标题用于解释目的,可以删除或修改以进行处理

预期输出

{  
   "Exome regions":[  
      {  
         "metric":"PIK3CA",
         "value":[  
            {  
               "metric":"Exons",
               "value":[  
                  "PIK3CA_Exon10",
                  {
                   "chromosome":"chr1",
                   "start":1000,
                   "end":1500
                  },
                  "PIK3CA_Exon13",
                 {
                   "chromosome":"chr1",
                   "start":1000,
                   "end":1500
                  },
                  "PIK3CA_Exon14",
                  {
                   "chromosome":"chr1",
                   "start":1000,
                   "end":1500
                  }
               ],
               "type":"set"
            },
            {  
               "metric":"Fraction of bases",
               "value":0.15,
               "type":"simple"
            },
            {  
               "metric":"Total_bases",
               "value":1927879,
               "type":"simple"
            }
         ],
         "type":"set"
      },

      {  
         "metric":"NRAS",
         "value":[  
            {  
               "metric":"Exons",
               "value":[  
                  "NRAS_Exon4",
                  {
                   "chromosome":"chr1",
                   "start":1000,
                   "end":1500
                  },
                  "NRAS_Amp_369",
                 {
                   "chromosome":"chr1",
                   "start":1000,
                   "end":1500
                  },
                  "NRAS_Amp_371",
                 {
                   "chromosome":"chr1",
                   "start":1000,
                   "end":1500
                  },
                  "NRAS_Amp_374",
                 {
                   "chromosome":"chr1",
                   "start":1000,
                   "end":1500
                  },
                  "NRAS_Amp_379",
                 {
                   "chromosome":"chr1",
                   "start":1000,
                   "end":1500
                  }
               ],
               "type":"set"
            },
            {  
               "metric":"Fraction of bases",
               "value":0.11,
               "type":"simple"
            },
            {  
               "metric":"Total_bases",
               "value":884111,
               "type":"simple"
            }
         ],
         "type":"set"
      }
   ]
}

提前感谢您的帮助!

PS: - 我需要添加更多信息,我必须编辑外显子字段并为每个外显子添加“染色体”、“开始”和“结束”。在这里,我给出了相同的开始和结束,但在实际情况下,每个外显子都不同。你能帮我解决这个问题吗? 此外,这些外显子的输入也可以用任何其他字符分隔。现在我用“;”分隔它

【问题讨论】:

  • 我需要更多帮助,是否可以拆分外显子并创建键值对。 PIK3CA,PIK3CA_Exon10;chr;2;100,PIK3CA_Exon13;chr;100;200,PIK3CA_Exon14;chr;2000;10000,1927879,12993042,0.15 Keys are Chromosome, Start and End, 值在外显子中,用“;”分隔

标签: json bioinformatics hierarchical-data jq


【解决方案1】:

这是一个使用函数来解析和组装输出的解决方案:

def parse:
  [
      inputs                     # read lines
    | split(",")                 # split into columns
    | select(length>0)           # eliminate blanks
    | .[:1] + [.[1:-3]] + .[-3:] # normalize columns
  ]
;
def simple(n;v): {metric:n, value:v|tonumber, type:"simple"};
def set(n;v):    {metric:n, value:v,          type:"set"};
def region:
  set(.[0]; [
      set("Exons"; .[1]),
      simple("Fraction of bases"; .[2]),
      simple("Total_bases"; .[3])
    ]
  )
;
{
   "Exome regions": parse | map(region)
}

示例运行(假设过滤器位于 filter.jq 中,数据位于 data.json 中)

$ jq -M -Rnr -f filter.jq data.json
{
  "Exome regions": [
    {
      "metric": "PIK3CA",
      "value": [
        {
          "metric": "Exons",
          "value": [
            "PIK3CA_Exon10",
            "PIK3CA_Exon13",
            "PIK3CA_Exon14"
          ],
          "type": "set"
        },
        {
          "metric": "Fraction of bases",
          "value": 1927879,
          "type": "simple"
        },
        {
          "metric": "Total_bases",
          "value": 12993042,
          "type": "simple"
        }
      ],
      "type": "set"
    },
    {
      "metric": "NRAS",
      "value": [
        {
          "metric": "Exons",
          "value": [
            "NRAS_Exon4",
            "NRAS_Amp_369",
            "NRAS_Amp_371",
            "NRAS_Amp_374",
            "NRAS_Amp_379"
          ],
          "type": "set"
        },
        {
          "metric": "Fraction of bases",
          "value": 884111,
          "type": "simple"
        },
        {
          "metric": "Total_bases",
          "value": 8062107,
          "type": "simple"
        }
      ],
      "type": "set"
    }
  ]
}

Try it online!


这里是修改后问题的解决方案:

def parse:
  [
      inputs                     # read lines
    | split(",")                 # split into columns
    | select(length>0)           # eliminate blanks
    | .[:1] + [.[1:-3]] + .[-3:] # normalize columns
  ]
;
def simple(n;v): {metric:n, value:v|tonumber, type:"simple"};
def set(n;v):    {metric:n, value:v,          type:"set"};
def exons(v):    [ v[] | split(";") | .[0], {"chromosome":.[1], "start":.[2], "end":.[3]} ];
def region:
  set(.[0]; [
      set("Exons"; exons(.[1])),
      simple("Fraction of bases"; .[2]),
      simple("Total_bases"; .[3])
    ]
  )
;

{ "Exome regions": parse | map(region) }

Try it online!

【讨论】:

  • 在可以避免的情况下使用 -s 选项,如这里,如果输入文件有很多行,则不建议这样做。如果您的 jq 没有inputs,那么只需使用reduce
  • 同意。我在parse 中用-ninputs 替换了-ssplit("\n")[] 的使用。
  • 我已经为修改后的问题添加了解决方案。
  • 这很棒,效果很好。是否有任何指针可以了解有关 jq 复杂函数的更多信息。
  • JSON like a boss 和与之配套的youtube 视频都不错。 jq cookbookrosettacode有很多很好的信息,jq source对学习很有帮助,尤其是builtin.jq
【解决方案2】:

这是一个解决方案,(a) 假设没有标题行,根据关于标题的注释(但见下文); (b) 不“啜饮”文件(即, 不会将整个文件读入内存); (c) 假设 jq 版本为inputs。 (如果你的jq没有inputs,那么相应地修改下面的就很容易了。)

def parse_row:
  split(",") 
  | length as $length
  | .[1: $length - 3] as $exons
  | { metric : .[0],
      value: [ { metric: "Exons",
                 value: $exons,
         type: "set" },
        { metric: "Fraction of bases",
                  value: (.[$length - 1] | tonumber),
          type: "simple"
        },
                { metric: "Total_bases",
                  value: (.[$length - 3] | tonumber),
                  type: "simple"
        }
        ],
        type: "set" 
    } ;

[inputs | parse_row]
| { "Exome regions": .}

对 jq 的适当调用应遵循以下几行:

jq -n -R -f program.jq input.txt

这会生成所需的 JSON。

(-R 用于“原始输入”。)

如果输入文件确实有标题行,则上述解决方案仍然有效,前提是您删除“-n”命令行选项。

请注意,虽然输入文件有逗号分隔值,但它并不是真正的 CSV 文件。

【讨论】:

  • 非常感谢高峰!这段代码就像一个魅力。是的,这更像是一个带有逗号分隔值的文件,而不是 CSV。
猜你喜欢
  • 2018-09-13
  • 1970-01-01
  • 2020-12-16
  • 2018-04-24
  • 1970-01-01
  • 1970-01-01
  • 2015-12-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多