【问题标题】:Find common and unique items between two arrays查找两个数组之间的共同项和唯一项
【发布时间】:2016-12-16 13:11:41
【问题描述】:

我使用带有 ansible 的 ec2.py 动态清单脚本来提取 ec2 主机及其标签名称的列表。它返回给我一个 JSON 列表,如下所示,

  "tag_aws_autoscaling_groupName_asg_test": [
    "aa.b.bb.55",
    "1b.b.c.d"
  ],

  "tag_aws_autoscaling_groupName_asg_unknown": [
    "aa.b.bb.55",
    "1b.b.c.e"
  ],

我正在使用 jq 来解析这个输出。

  1. 如何仅提取这两个 ASG 共有的字段?
  2. 如何仅提取这两个 ASG 独有的字段?

【问题讨论】:

  • 1.请提供至少一个包含有效 JSON 输入和预期输出的最小示例。 2.你的问题在几个方面都非常不清楚。例如,当您说“字段”时,您是指键名(例如“tag_aws_autoscaling_groupName_asg_test”)还是键值(数组)?

标签: arrays json jq set-intersection set-difference


【解决方案1】:

差异/2

由于 jq 的“-”运算符在数组上定义的方式,unique 的一次调用足以产生“唯一”答案:

def difference($a; $b): ($a | unique) - $b;

同样,对于对称差,单次排序操作就足以产生一个“唯一”的值:

def sdiff($a; $b): (($a-$b) + ($b-$a)) | unique;

相交/2

这是一个更快的 intersect/2 版本,它应该适用于所有版本的 jq —— 它消除了 group_by 以支持 sort

def intersect(x;y):
  ( (x|unique) + (y|unique) | sort) as $sorted
  | reduce range(1; $sorted|length) as $i
      ([];
       if $sorted[$i] == $sorted[$i-1] then . + [$sorted[$i]] else . end) ;

intersection/2

如果您有 jq 1.5,那么这里有一个类似但仍然明显更快的 set-intersection 函数:它在两个数组的 set-intersection 中生成元素流:

def intersection(x;y):
  (x|unique) as $x | (y|unique) as $y
  | ($x|length) as $m
  | ($y|length) as $n
  | if $m == 0 or $n == 0 then empty
    else { i:-1, j:-1, ans:false }
    | while(  .i < $m and .j < $n;
        $x[.i+1] as $nextx
        | if $nextx == $y[.j+1] then {i:(.i+1), j:(.j+1), ans: true, value: $nextx}
          elif  $nextx < $y[.j+1] then .i += 1 | .ans = false
          else  .j += 1 | .ans = false
          end )
    end
  | if .ans then .value else empty end ;

【讨论】:

    【解决方案2】:

    要查找两个数组之间的共同项,只需在两者之间执行集合交集。没有可用的交集函数,但它应该足够简单,可以自行定义。取每个数组的唯一项,按值分组,然后取一组中超过 1 个的项。

    def intersect($a; $b): [($a | unique)[], ($b | unique)[]]
        | [group_by(.)[] | select(length > 1)[0]];
    

    使用它来查找公共元素(假设您的输入实际上是一个有效的 json 对象):

    $ jq 'def intersect($a; $b): [($a | unique)[], ($b | unique)[]]
        | [group_by(.)[] | select(length > 1)[0]];
    intersect(.tag_aws_autoscaling_groupName_asg_test;
              .tag_aws_autoscaling_groupName_asg_unknown)' < input.json
    [
      "aa.b.bb.55"
    ]
    

    要查找数组唯一的项目,只需执行设置差异。

    $ jq 'def difference($a; $b): ($a | unique) - ($b | unique);
    difference(.tag_aws_autoscaling_groupName_asg_test;
               .tag_aws_autoscaling_groupName_asg_unknown)' < input.json
    [
      "1b.b.c.d"
    ]
    

    【讨论】:

    • 非常感谢 Jeff 和 Peak。您的两个输入都非常有价值,并帮助了我。在为每个标签使用可能对其他人有帮助的变量之后,我的代码中的实际行.. match_hosts=$($inventory_script_dir/ec2.py | jq --arg c "$tag1" --arg d "$tag2" 'def intersect( a; b): [(a | unique)[], (b | unique)[]] | [group_by(.)[] | select(length > 1)[0]];intersect(.[$c]; .[$d])')
    猜你喜欢
    • 1970-01-01
    • 2021-10-14
    • 2015-10-27
    • 2020-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-09
    相关资源
    最近更新 更多