BASH中两个数组的交集

Bog*_*dan 15 scripting bash array

我有两个这样的数组:

A=(vol-175a3b54 vol-382c477b vol-8c027acf vol-93d6fed0 vol-71600106 vol-79f7970e vol-e3d6a894 vol-d9d6a8ae vol-8dbbc2fa vol-98c2bbef vol-ae7ed9e3 vol-5540e618 vol-9e3bbed3 vol-993bbed4 vol-a83bbee5 vol-ff52deb2)
B=(vol-175a3b54 vol-e38d0c94 vol-2a19386a vol-b846c5cf vol-98c2bbef vol-7320102b vol-8f6226cc vol-27991850 vol-71600106 vol-615e1222)
Run Code Online (Sandbox Code Playgroud)

数组未排序,甚至可能包含重复元素。

  1. 我想使这两个数组相交并将元素存储在另一个数组中。我该怎么做?

  2. 另外,如何获取出现在 B 中但在 A 中不可用的元素列表?

cam*_*amh 19

comm(1)是一种比较两个列表的工具,可以为您提供两个列表之间的交集或差异。列表需要排序,但这很容易实现。

要将您的数组放入适合于的排序列表comm

$ printf '%s\n' "${A[@]}" | LC_ALL=C sort
Run Code Online (Sandbox Code Playgroud)

这会将数组 A 变成一个排序列表。对 B 做同样的事情。

要使用comm返回交集:

$ comm -1 -2 file1 file2
Run Code Online (Sandbox Code Playgroud)

-1 -2 说要删除 file1 (A) 独有的条目和 file2 (B) 独有的条目 - 两者的交集。

让它返回 file2 (B) 中的内容而不是 file1 (A) 中的内容:

$ comm -1 -3 file1 file2
Run Code Online (Sandbox Code Playgroud)

-1 -3 说要删除文件 1 独有的条目和两者共有的条目 - 只留下文件 2 独有的条目。

要将两个管道送入comm,请使用 的“流程替换”功能bash

$ comm -1 -2 <(pipeline1) <(pipeline2)
Run Code Online (Sandbox Code Playgroud)

要在数组中捕获它:

$ C=($(command))
Run Code Online (Sandbox Code Playgroud)

把它们放在一起:

# 1. Intersection
$ C=($(comm -12 <(printf '%s\n' "${A[@]}" | LC_ALL=C sort) <(printf '%s\n' "${B[@]}" | LC_ALL=C sort)))

# 2. B - A
$ D=($(comm -13 <(printf '%s\n' "${A[@]}" | LC_ALL=C sort) <(printf '%s\n' "${B[@]}" | LC_ALL=C sort)))
Run Code Online (Sandbox Code Playgroud)


ken*_*chi 7

有一种相当优雅且有效的方法可以使用uniq\xe2\x80\x94 来做到这一点,但是,我们需要消除每个数组中的重复项,只留下唯一的项目。如果要保存重复项,只有一种方法“循环遍历两个数组并进行比较”。

\n

考虑我们有两个数组:

\n
A=(vol-175a3b54 vol-382c477b vol-8c027acf vol-93d6fed0 vol-71600106 vol-79f7970e vol-e3d6a894 vol-d9d6a8ae vol-8dbbc2fa vol-98c2bbef vol-ae7ed9e3 vol-5540e618 vol-9e3bbed3 vol-993bbed4 vol-a83bbee5 vol-ff52deb2)\nB=(vol-175a3b54 vol-e38d0c94 vol-2a19386a vol-b846c5cf vol-98c2bbef vol-7320102b vol-8f6226cc vol-27991850 vol-71600106 vol-615e1222)\n
Run Code Online (Sandbox Code Playgroud)\n

首先,让我们将这些数组转换为集合。我们会这样做,因为存在数学运算交集,就像集合的交集一样,集合是不同对象的集合,不同的唯一的。老实说,如果我们谈论列表或序列,我不知道什么是“交集”。虽然我们可以从序列中选出一个子序列,但是这个操作(选择)的含义略有不同。

\n

那么,让我们一起变身吧!

\n
A=($(echo "${A[@]}" | sed 's/ /\\n/g' | sort | uniq))\nB=($(echo "${B[@]}" | sed 's/ /\\n/g' | sort | uniq))\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 路口:

    \n
    echo "${A[@]} ${B[@]}" | sed 's/ /\\n/g' | sort | uniq -d\n
    Run Code Online (Sandbox Code Playgroud)\n

    如果要将元素存储在另一个数组中:

    \n
    intersection_set=($(echo "${A[@]} ${B[@]}" | sed 's/ /\\n/g' | sort | uniq -d))\n\necho "${intersection_set[@]} (elements count: ${#intersection_set[@]})"\nvol-175a3b54 vol-71600106 vol-98c2bbef (elements count: 3)\n
    Run Code Online (Sandbox Code Playgroud)\n

    uniq -d意味着只打印重复的行。

    \n
  2. \n
  3. B获取中出现且不可用的元素列表A,即B\\A

    \n
    echo "${A[@]} ${B[@]}" | sed 's/ /\\n/g' | sort | uniq -d | xargs echo "${B[@]}" | sed 's/ /\\n/g' | sort | uniq -u\n
    Run Code Online (Sandbox Code Playgroud)\n

    uniq -u意味着只打印唯一的行。

    \n

    或者,保存在变量中:

    \n
    subtraction_set=($(echo "${A[@]} ${B[@]}" | sed 's/ /\\n/g' | sort | uniq -d | xargs echo "${B[@]}" | sed 's/ /\\n/g' | sort | uniq -u))\n\necho "${subtraction_set[@]} (elements count: ${#subtraction_set[@]})"\nvol-27991850 vol-2a19386a vol-615e1222 vol-7320102b vol-8f6226cc vol-b846c5cf vol-e38d0c94 (elements count: 7)\n
    Run Code Online (Sandbox Code Playgroud)\n

    因此,首先我们得到A和的交集B(这只是它们之间的重复项的集合),说它是A/\\B,然后我们使用B和 的交集的反转操作A/\\B(这只是唯一的元素),所以我们得到B\\A = ! (B /\\ (A/\\B))

    \n
  4. \n
\n

PSuniq由理查德·M·斯托曼 (Richard M. Stallman) 和大卫·麦肯齐 (David MacKenzie) 撰写。

\n

  • 顺便说一句,这是一个非常巧妙的解决方案,使用“uniq -d”。 (2认同)