简体   繁体   English

Jq - 计算 JSON 中每个数组的长度并更新它

[英]Jq - calculate length of each array in JSON and update it

I have the following JSON array我有以下 JSON 数组

[
  {
    "name": "California",
    "Data": {
      "AB00001": ["Los Angeles", "San Francisco", "Sacramento", "Fresno", "San Jose", "Palo Alto"]
    }
  },
  {
    "name": "Oregon",
    "Data": {
      "CD00002": ["Portland", "Salem", "Hillsboro"]
    }
  },
  {
    "name": "Washington",
    "Data": {
      "EF00003": ["Seattle", "Tacoma", "Spokane", "Bellevue"]
    }
  }
]

With jq '.[].Data[] | length'jq '.[].Data[] | length' jq '.[].Data[] | length' I can get the length of each array, but I need to create Length key under Data object and assign to it the length of the array which is in the Data object. jq '.[].Data[] | length'我可以获得每个数组的长度,但我需要在Data对象下创建Length键,并为其分配Data对象中数组的长度。 The result should look like the following:结果应如下所示:

[
    {
        "name": "California",
        "Data": {
            "ID00001": ["Los Angeles", "San Francisco", "Sacramento", "Fresno", "San Jose", "Palo Alto"],
            "Length": 6
        }
    },
    {
        "name": "Oregon",
        "Data": {
            "ID00002": ["Portland", "Salem", "Hillsboro"],
            "Length": 3
        }
    },
    {
        "name": "Washington",
        "Data": {
            "ID00003": ["Seattle", "Tacoma", "Spokane", "Bellevue"],
            "Length": 4
        }
    }
]

The problem here is that in my example the object name holding the array ( Data in my example) and the array name itself ( AB00001/CD00002/EF00003 ) are not known in advance.这里的问题是,在我的示例中,保存数组的对象名称(在我的示例中为Data )和数组名称本身( AB00001/CD00002/EF00003 )事先并不知道。 However, the values of the name key is known.但是, name键的值是已知的。 Also, the array might be empty, so in this case, the Length should be 0.此外,数组可能为空,因此在这种情况下, Length应为 0。

So the algorithm pseudocode should be either of one as I've envisioned:所以算法伪代码应该是我所设想的其中之一:

for the whole JSON file, 
if the type is an array, 
then assign it to the Length key created in the parent object of that array, 
next

or或者

For the specific value in the name key, select,
if the entry contains an array
create Length key in the array's parent object, 
assign the length of the array,
select the next value of the name key

I tried to use with jq's walk or .. for the first approach but didn't work.我尝试使用 jq's walk..作为第一种方法,但没有用。 What are the alternatives?有哪些替代方案?

A solution to the immediate problem (in which .Data is a single-key object with an array-valued key) could be as simple as:解决当前问题(其中 .Data 是具有数组值键的单键对象)的解决方案可能很简单:

map( .Data.Length = (.Data[]|length) )

This can be adapted to the more general problem in steps.这可以逐步适应更一般的问题。 First, consider this generalization:首先,考虑这个概括:

map( .Data |= if length==1 and (.[]|type) == "array" 
              then .Length = (.[]|length) 
              else . end )

Solution解决方案

To make the actual solution easier to understand, let's define a helper function:为了使实际解决方案更容易理解,让我们定义一个辅助函数:

def addLength:
   (first(keys_unsorted[] as $k
          | select(.[$k]|type == "object")
          | .[$k]
          | keys_unsorted[] as $l 
          | select(.[$l]|type == "array")
          | [$k,$l]) // null) as $a
   | if $a 
     then setpath([$a[0],"Length"]; getpath($a)|length)
     else .
     end;

A general solution can now be written using walk :现在可以使用walk编写通用解决方案:

walk(if type == "object" and has("name")
     then addLength
     else . end)

This seems to be what you want:这似乎是你想要的:

jq '.[].Data |= . + { length:.[]|length } ' data.json

Output:输出:

[
  {
    "name": "California",
    "Data": {
      "AB00001": [
        "Los Angeles",
        "San Francisco",
        "Sacramento",
        "Fresno",
        "San Jose",
        "Palo Alto"
      ],
      "length": 6
    }
  },
  {
    "name": "Oregon",
    "Data": {
      "CD00002": [
        "Portland",
        "Salem",
        "Hillsboro"
      ],
      "length": 3
    }
  },
 # etc.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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