Yanıtlar:
Öğelerin NUL ve newline dışındaki karakter dizeleri olduğunu varsayalım (newline'ın dosya adlarında geçerli olduğuna dikkat edin), bir kümeyi her satırda bir öğe içeren bir metin dosyası olarak temsil edebilir ve standart Unix yardımcı programlarından bazılarını kullanabilirsiniz.
$ grep -Fxc 'element' set # outputs 1 if element is in set
# outputs >1 if set is a multi-set
# outputs 0 if element is not in set
$ grep -Fxq 'element' set # returns 0 (true) if element is in set
# returns 1 (false) if element is not in set
$ awk '$0 == "element" { s=1; exit }; END { exit !s }' set
# returns 0 if element is in set, 1 otherwise.
$ awk -v e='element' '$0 == e { s=1; exit } END { exit !s }'
$ comm -12 <(sort set1) <(sort set2) # outputs intersect of set1 and set2
$ grep -xF -f set1 set2
$ sort set1 set2 | uniq -d
$ join -t <(sort A) <(sort B)
$ awk '!done { a[$0]; next }; $0 in a' set1 done=1 set2
$ cmp -s <(sort set1) <(sort set2) # returns 0 if set1 is equal to set2
# returns 1 if set1 != set2
$ cmp -s <(sort -u set1) <(sort -u set2)
# collapses multi-sets into sets and does the same as previous
$ awk '{ if (!($0 in a)) c++; a[$0] }; END{ exit !(c==NR/2) }' set1 set2
# returns 0 if set1 == set2
# returns 1 if set1 != set2
$ awk '{ a[$0] }; END{ exit !(length(a)==NR/2) }' set1 set2
# same as previous, requires >= gnu awk 3.1.5
$ wc -l < set # outputs number of elements in set
$ awk 'END { print NR }' set
$ sed '$=' set
$ comm -23 <(sort -u subset) <(sort -u set) | grep -q '^'
# returns true iff subset is not a subset of set (has elements not in set)
$ awk '!done { a[$0]; next }; { if !($0 in a) exit 1 }' set done=1 subset
# returns 0 if subset is a subset of set
# returns 1 if subset is not a subset of set
$ cat set1 set2 # outputs union of set1 and set2
# assumes they are disjoint
$ awk 1 set1 set2 # ditto
$ cat set1 set2 ... setn # union over n sets
$ sort -u set1 set2 # same, but doesn't assume they are disjoint
$ sort set1 set2 | uniq
$ awk '!a[$0]++' set1 set2 # ditto without sorting
$ comm -23 <(sort set1) <(sort set2)
# outputs elements in set1 that are not in set2
$ grep -vxF -f set2 set1 # ditto
$ sort set2 set2 set1 | uniq -u # ditto
$ awk '!done { a[$0]; next }; !($0 in a)' set2 done=1 set1
$ comm -3 <(sort set1) <(sort set2) | tr -d '\t' # assumes not tab in sets
# outputs elements that are in set1 or in set2 but not both
$ sort set1 set2 | uniq -u
$ cat <(grep -vxF -f set1 set2) <(grep -vxF -f set2 set1)
$ grep -vxF -f set1 set2; grep -vxF -f set2 set1
$ awk '!done { a[$0]; next }; $0 in a { delete a[$0]; next }; 1;
END { for (b in a) print b }' set1 done=1 set2
Bir kümenin tüm olası alt kümeleri, satır başına bir tane olmak üzere ayrılmış bir alan görüntülüyor:
$ p() { [ "$#" -eq 0 ] && echo || (shift; p "$@") |
while read r; do printf '%s %s\n%s\n' "$1" "$r" "$r"; done; }
$ p $(cat set)
(öğelerin SPC, SEKME (varsayılan değer olduğu varsayılarak $IFS
), ters eğik çizgi, joker karakterler içermediğini varsayar ).
$ while IFS= read -r a; do while IFS= read -r b; do echo "$a, $b"; done < set1; done < set2
$ awk '!done { a[$0]; next }; { for (i in a) print i, $0 }' set1 done=1 set2
$ comm -12 <(sort set1) <(sort set2) # does not output anything if disjoint
$ awk '++seen[$0] == 2 { exit 1 }' set1 set2 # returns 0 if disjoint
# returns 1 if not
$ wc -l < set # outputs 0 if the set is empty
# outputs >0 if the set is not empty
$ grep -q '^' set # returns true (0 exit status) unless set is empty
$ awk '{ exit 1 }' set # returns true (0 exit status) if set is empty
$ sort set | head -n 1 # outputs the minimum (lexically) element in the set
$ awk 'NR == 1 { min = $0 }; $0 < min { min = $0 }; END { print min }'
# ditto, but does numeric comparison when elements are numerical
$ sort test | tail -n 1 # outputs the maximum element in the set
$ sort -r test | head -n 1
$ awk '$0 > max { max = $0 }; END { print max }'
# ditto, but does numeric comparison when elements are numerical
Hepsi http://www.catonmat.net/blog/set-operations-in-unix-shell-simplified/ adresinde bulunabilir.
sort set1 set2 | uniq -d
çoklu kümeler için çalışmaz. Kullanmayı düşünün sort <(sort -u set1) <(sort -u set2) | uniq -d
.
Sırala. Kendinizi sıralamakla başa çıkmanız gerekir, ancak comm
bunu yapmak için kullanılabilir, her bir çizgiyi belirlenmiş bir üye olarak ele alır: -12
kavşak -13
için, fark için. (Ve -23
yani,, farkı çevrilmiş verir set2 - set1
yerine set1 - set2
.) Birliği olan sort -u
bu kurulum.
Belirli bir aracı bilmiyorum ama bunu yapmak için küçük bir betik yazmak için Python'u ve set sınıfını ve işleçlerini kullanabilirsiniz.
Sınav için:
Python> s1 = set(os.listdir("/bin"))
Python> s2 = set(os.listdir("/usr/bin"))
Python> s1 & s2
set(['awk',
'basename',
'chroot', ...
Python> import os
Küçük konsol aracı “setop”, 16.10'dan beri Debian Stretch ve Ubuntu'da mevcut. Üzerinden alabilirsiniz
sudo apt install setop
İşte bazı örnekler. Çalıştırılacak setler farklı giriş dosyaları olarak verilmiştir:
setop input # is equal to "sort input --unique"
setop file1 file2 --union # option --union is default and can be omitted
setop file1 file2 file3 --intersection # more than two inputs are allowed
setop file1 - --symmetric-difference # ndash stands for standard input
setop file1 -d file2 # all elements contained in 1 but not 2
Boolean sorguları yalnızca EXIT_SUCCESS
doğru olduğunda ve EXIT_FAILURE
aksi takdirde bir mesaj olduğunda geri döner . Bu şekilde, setop kabukta kullanılabilir.
setop inputfile --contains "value" # is element value contained in input?
setop A.txt B.txt --equal C.txt # union of A and B equal to C?
setop bigfile --subset smallfile # analogous --superset
setop -i file1 file2 --is-empty # intersection of 1 and 2 empty (disjoint)?
Girdi akışlarının nasıl düzenli olarak ifade edileceği ile nasıl ayrıştırılacağını tam olarak açıklamak da mümkündür:
setop input.txt --input-separator "[[:space:]-]"
bir boşluk (yani \v
\t
\n
\r
\f
veya boşluk) veya bir eksi işaretinin öğeler arasında bir ayırıcı olarak yorumlandığı anlamına gelir (varsayılan değer yeni satırdır, yani giriş dosyasının her satırı bir öğedir).setop input.txt --input-element "[A-Za-z]+"
elemanların yalnızca latin karakterlerinden oluşan sözcükler olduğu anlamına gelir, diğer tüm karakterlerin öğeler arasında ayırıcı olduğu kabul edilir.Ayrıca, yapabilirsiniz
--count
çıkış kümesinin tüm elemanları,--trim
tüm girdi öğeleri (yani boşluk, virgül vb. önceki tüm istenmeyen ve sonraki karakterleri siler),--include-empty
,--ignore-case
,--output-separator
Çıkış akışının elemanları arasındakileri ayarlayın (varsayılan \n
)Bkz man setop
veya github.com/phisigma/setop fazla bilgi için.
Bir dosyayı satır kümesi olarak görüyorsanız ve dosyalar sıralanırsa, var comm
.
Bir dosyayı (çok) satır kümesi olarak görüyorsanız ve satırlar sıralanmamışsa, grep
fark ve kesişme yapabilir (ayarlanan fark ve kesişme elde eder, ancak çoklu kümelerin sayımına saygı göstermez). Sendika adil cat
.
grep -xF -f small large >intersection
grep -vxF -f small large >difference
cat small large >union
Bunu yapmak için çeşitli yerlerde benim için oldukça faydalı olan küçük bir araç yazdım. UI cilalanmamış ve çok büyük dosyaların performans özelliklerini (tüm listeyi belleğe okuduğundan) emin değilim ama "benim için çalışıyor". Program https://github.com/nibrahim/lines adresinde yer almaktadır . Python'da. Kullanarak alabilirsiniz pip install lines
.
Şu anda iki dosyanın birliğini, kesişimini, farkını ve simetrik farkını desteklemektedir. Giriş dosyasının her satırı bir kümenin öğesi olarak değerlendirilir.
Aynı zamanda iki ekstra işlem daha var. Bir dosyadaki boş satırları sıkmak ve ikincisi (benim için çok faydalı oldu) dosyaya bakmak ve onu benzer dizgilerin kümelerine bölmektir. Genel modelle uyuşmayan bir listedeki dosyaları aramak için buna ihtiyacım vardı.
Geribildirimden memnuniyet duyarım.
Dosya sistemi dosya adlarını (yollar dahil tüm dosya adları) benzersiz olarak değerlendirir.
Operasyonlar?
Yeni bir birleşim kümesi elde etmek için a / ve b / 'deki dosyaları boş c / c dizinine kopyalayabilirsiniz.
-e name
Kesişme veya farkı bulmak için, dosyalarda ya da döngülerde bulunan dosya testleriyle , iki veya daha fazla dizinde bulunan dosyaları kontrol edebilirsiniz.
Buradaki en iyi cevap: Setdown (özel bir araç)
Set işlemlerini cli'dan gerçekleştiren setdown adlı bir program yazdım.
Makefile'de yazdıklarınıza benzer bir tanım yazarak set işlemlerini gerçekleştirebilir:
someUnion: "file-1.txt" \/ "file-2.txt"
someIntersection: "file-1.txt" /\ "file-2.txt"
someDifference: someUnion - someIntersection
Oldukça havalı ve kontrol etmelisin. Şahsen ben set işlemleri yapmak için iş için oluşturulmamış geçici komutları kullanmanızı önermiyorum. Gerçekten birçok set işlemi yapmanız gerektiğinde veya birbirine bağlı herhangi bir işleminiz varsa, iyi çalışmaz. . Sadece bu değil, setdown, diğer set işlemlerine bağlı set işlemleri yazmanıza izin verir!
Her halükarda, bence oldukça havalı ve tamamen kontrol etmelisin.
İle zsh
diziler ( zsh
diziler bayt herhangi bir rasgele sekansı, hatta 0 içerebilir).
(ayrıca typeset -U array
, öğelerinin benzersiz olduğunu garanti etmek için yapabileceğinizi unutmayın ).
if ((${array[(Ie)$element]})); then
echo '$element is in $array'
fi
(kullanarak I
son görüldüğü dizinini elde etmek için, dizi simge bayrağı $element
bulunmazsa dizisinde (ya da 0). çıkarmak e
için ( e
için) XACT $element
bir model olarak alınmalıdır)
if ((n = ${(M)#array:#$element})); then
echo "\$element is found $n times in \$array'
fi
${array:#pattern}
Ksh yıllardan bir varyasyon olmak kaldırır sadece kalıpla eşleşen lider kısmını kaldırmak aksine desenle eşleşen elemanları. (İçin eşleştirilmiş ) anlama tersine döner ve kaldırır fakat eşleşen elemanlar (kullanımı için bir model olarak kabul edilebilir).${var#pattern}
(M)
$~element
common=("${(@)set1:*set2}")
${set1:*set2}
dizi kesişimi yapar, ancak "${(@)...}"
boş öğeleri korumak için sözdizimi gerekir.
[[ ${(j: :)${(q)array1}} = ${(j: :)${(q)array2}} ]]
Dizilerin aynı olup olmadığını test eder (ve aynı sırada). q
Parametre genişletme bayrağı (gibi şeylerle sorunlardan kaçınmak için elemanlar tırnak a=(1 "2 3")
vs b=("1 2" 3)
) ve (j: :)
bir dize karşılaştırma yapmadan önce boşluk onlara katılır.
Aynı öğelere sahip olduklarını kontrol etmek için, sırasına bakmaksızın, sıralamak için o
bayrağı kullanın. Ayrıca u
çoğaltmaları kaldırmak için bayrağa (benzersiz) bakın .
[[ ${(j: :)${(qo)array1}} = ${(j: :)${(qo)array2}} ]]
n=$#array
if ((${#array1:*array2} == ${#array2})); then
echo '$array2 is included in $array1'
fi
union=("$array1[@]" "$array2[@]")
(yukarıya bakın typeset -U
veya u
yinelenenleri almak için parametre genişletme bayrağına bakın ). Yine, boş dize olası değerlerden biri değilse, aşağıdakileri basitleştirebilirsiniz:
union=($array1 $array2)
complement=("${(@)array1:|array2}")
Bunun unsurları içinde $array1
değil $array2
.
min=${${(o)array}[1]} max=${${(o)array}[-1]}
min=${${(no)array}[1]} max=${${(no)array}[-1]}