求数组的补集?

求数组的补集?

继自这个问题,我希望从文件中提取 10 行随机行,现在我希望将剩余的 90 行作为单独的文件。

由于文档有 100 行,索引从 1 到 100,因此问题归结为查找 的补集ind1, 2, ..., 100其中

ind=$(shuf -i 1-100 -n 10 | sort -n)

所以我的问题是

  1. 如何1, 2, ..., 100有效地生成数组?和
  2. 看来这个可以用 来完成comm。如果是这样,我应该如何处理comm数组(而不是文件)?

答案1

根据我在其他线程中的建议:

awk '
  BEGIN { srand(); do a[int(100*rand()+1)]; while (length(a)<10) }
  NR in a
' ~/orig.txt > ~/short.txt

可以将其更改为创建两个文件:

awk -v range=100 -v offset=1 -v amount=10 '
  BEGIN { srand(); do a[int(range*rand()+offset)]; while (length(a)<amount) }
  NR in a    { print > "short.txt" }
  !(NR in a) { print > "rest.txt" }
' ~/orig.txt

(请注意,在内部awk不能使用~。不过,可以使用HOMEthrough ENVIRON[],如:print > ENVIRON["HOME"] "/short.txt"或 resp., print > ENVIRON["HOME"] "/rest.txt"。)

答案2

好吧,转念一想——我工作过方式太难了。你只需要这个:

shuf -i 1-100 -n10 |
sed 's/$/{p;b\n}/' |
sed -nf - -e 'w separate_file' infile >outfile

尽管您可能需要一个文字换行符来代替替换n中的sed。无论如何,它的作用与下面相同 - 它只是不必费心执行所有其他 90 行 - 它们只是就位,因为它们在文件中 - 所以它们不需要任何特殊考虑。

这是整个交易:

set  " $(shuf -i 1-100 -n 10) "
while [ "$((i+=1))" -le 100 ]
do    [ -z "${1##*[!0-9]$i[!0-9]*}" ]
      printf "$i%.$((!$?))s%.$?s\n" p H 
done| sed -nf - -e '$!d;x;s/.//p' <infile >outfile

在那里 - 我们基本上只是编写一个sed如下所示的脚本:

1H
2H
3H
4p
5H
...
90p
91H
...

依此类推,直到 100。在最后一行 - 在所有随机选择的行都已被p打印之后,我们x更改为H旧空间,s///替换掉第一个插入的\newline 字符,并p打印其余的部分。

要在没有 shell 循环的情况下执行此操作,您可以执行以下操作:

set  "$(shuf -i 1-100 -n 10)"
{ seq 100 | grep -Fxv "$1"; echo "$1"; } |
sed '1,90s/$/H/;91,$s/$/p/' |
sed -nf - -e '$!d;x;s/.//p' <infile >outfile

但我不确定在这种规模上这是否会有好处。

不管怎样,我使用了一个seq 100输出文件作为测试,并在运行它后打印出来......

3
4
5
19
57
63
64
73
80
88
1
2
6
7
8
9
10
11
12
13
14
15
16
...

...对于未包含在初始随机 100 中的所有行,一直到 100。

答案3

这是使用 bash 的另一种解决方案。首先,您可能希望从 ind 变量创建一个数组:

ind=($(shuf -i 1-100 -n 10 | sort -n))

要创建一个包含 1..100 范围内的数字的数组,一个简单的方法是:

numbers=({1..100})

为了获得补集,我将使用 uniq -u。该命令可以从已排序的列表中排序出所有重复项。最后的粘贴命令只是将所有值再次放入一行中。

complement=($(echo ${ind[*]} ${numbers[*]} | sed 's/ /\n/g' | sort -n | uniq -u | paste -sd " " - ))
echo ${complement[*]}

只是重新思考这个问题,所有这些也可以在没有 bash 数组的情况下完成:

ind=$(shuf -i 1-100 -n 10 | sort -n)
echo $ind {1..100} | sed 's/ /\n/g' | sort -n | uniq -u | paste -sd " " -

答案4

我相信您可以在命令行上完成所有操作,但有些问题使用实际的编程语言可以更好地解决。举个例子,基于 python 的问题解决方案是:

import random
import pprint

with open("file.txt", "w") as f:
  # create a file filled with numbers from 00 to 99
  f.writelines(map(lambda x: "%02d\n" % x, range(100)))

with open("file.txt") as f:
  # read it and assign each line to array, strip newlines 
  ar = set(map(lambda x: x.strip(), f.readlines()))

selection = set(random.sample(ar, 10))
rest = ar - selection

pprint.pprint(selection)
pprint.pprint(rest)

相关内容