jq:从对象中选择键的子集

jq: selecting a subset of keys from an object

给定一个数组中的 json 键字符串输入,return 一个对象,该对象仅包含在原始对象和输入数组中具有键的条目。

我有一个解决方案,但我认为它不够优雅({($k):$input[$k]} 感觉特别笨拙...),这是我学习的机会。

jq -n '{"1":"a","2":"b","3":"c"}'   \
    | jq --arg keys '["1","3","4"]' \
    '. as $input 
     | ( $keys | fromjson )
     | map( . as $k
          | $input
          | select(has($k))
          | {($k):$input[$k]}
          )
     | add'

有什么办法可以清理吗?

我觉得 是一个很好的起点,但我无法让它发挥作用。

您可以使用这个过滤器:

with_entries(
    select(
        .key as $k | any($keys | fromjson[]; . == $k)
    )
)

这里有一些补充说明

对于输入对象 {"key1":1, "key2":2, "key3":3} 我想删除所有不在所需键集中的键 ["key1","key3","key4"]

 jq -n --argjson desired_keys '["key1","key3","key4"]'  \
       --argjson input '{"key1":1, "key2":2, "key3":3}' \
    ' $input
    | with_entries(
          select(
              .key == ($desired_keys[])
          )
       )'

with_entries{"key1":1, "key2":2, "key3":3}转换成下面的键值对数组,并将select语句映射到数组上,然后将结果数组转回对象。

这里是with_entries语句中的内部对象。

[
  {
    "key": "key1",
    "value": 1
  },
  {
    "key": "key2",
    "value": 2
  },
  {
    "key": "key3",
    "value": 3
  }
]

然后我们可以 select 这个数组中满足我们条件的键。

这就是奇迹发生的地方...这里是这个命令中间发生的事情。以下命令获取扩展的值数组并将它们转换为我们可以 select 来自的对象列表。

jq -cn '{"key":"key1","value":1}, {"key":"key2","value":2}, {"key":"key3","value":3}
      | select(.key == ("key1", "key3", "key4"))'

这将产生以下结果

{"key":"key1","value":1}
{"key":"key3","value":3}

with entries 命令可能有点棘手,但很容易记住它需要一个过滤器并定义如下

def with_entries(f): to_entries|map(f)|from_entries;

这与

相同
def with_entries(f): [to_entries[] | f] | from_entries;

问题的另一部分让人感到困惑的是 ==

右侧的多个匹配项

考虑以下命令。我们看到输出是所有左手列表和右手列表的外部产生式。

jq -cn '1,2,3| . == (1,1,3)'
true
true
false
false
false
false
false
false
true

如果该谓词在 select 语句中,我们将在谓词为真时保留输入。请注意,您也可以在此处复制输入。

jq -cn '1,2,3| select(. == (1,1,3))'
1
1
3

Jeff 的回答有几个不必要的低效问题,假设使用 --argjson keys 而不是 --arg keys

with_entries( select( .key as $k | $keys | index($k) ) )

内部检查解决方案:

jq 'with_entries(select([.key] | inside(["key1", "key2"])))'

内部操作员大部分时间都在工作;然而,我刚刚发现内部运算符有副作用,有时它 selected 键不需要,假设输入是 { "key1": val1, "key2": val2, "key12": val12 } 和 select by inside(["key12"]) 它会 select "key1""key12"

如果需要精确匹配,请使用 in 运算符:像这样只会 select .key2.key12

jq 'with_entries(select(.key | in({"key2":1, "key12":1})))'

因为 in 运算符只检查对象中的键(或数组中的索引 exists?),这里必须用对象语法编写,以所需的键作为键,但值无关紧要; in 运算符的使用并不是这个目的的完美选择,我希望看到 Javascript ES6 包含 API 的反向版本以 jq builtin

实现

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes

jq 'with_entries(select(.key | included(["key2", "key12"])))'

检查项目 .key 是否来自数组 included?