我需要一个Bash脚本,它将获得一个包含n个元素作为输入的数组,并返回该数组的powerset。
因此对于array=(a, b, c, d)
,输出应为
a
ab
abc
abcd
abd
ac
acd
b
bc
bcd
c
cd
d
请注意,任何元素都不应重复(aab,accd,abbc无效),abc与cba相同(顺序不重要)。
我找到的类似问题的每个解决方案都给出了固定长度(长度为2或3的组合)或允许重复(如aacd),即使对于其他语言(不是我可以用其他语言做很多......)
我想出了这个:
string='a b c d'
read -a array <<< "$string"
count="${#array[@]}"
level=0
for (( level = 0; level < $count; level++ )); do
for (( i = $level; i < $count; i++ )); do
output+=" ${array[$i]}"
echo $output
done
output=''
done
我的输出是
a
a b
a b c
a b c d
b
b c
b c d
c
c d
d
它缺少一些条目,如ac,ad,abd ......
有什么想法吗?
答案 0 :(得分:7)
#! /bin/bash
items=(a b c d)
n=${#items[@]}
powersize=$((1 << $n))
i=0
while [ $i -lt $powersize ]
do
subset=()
j=0
while [ $j -lt $n ]
do
if [ $(((1 << $j) & $i)) -gt 0 ]
then
subset+=("${items[$j]}")
fi
j=$(($j + 1))
done
echo "'${subset[@]}'"
i=$(($i + 1))
done
输出:
''
'a'
'b'
'a b'
'c'
'a c'
'b c'
'a b c'
'd'
'a d'
'b d'
'a b d'
'c d'
'a c d'
'b c d'
'a b c d'
答案 1 :(得分:4)
这有效:
$ p(){ eval echo $(printf "{%s,}" "$@"); }
$ p a b c d
abcd abc abd ab acd ac ad a bcd bc bd b cd c d
或者,更便携:
p() {
[ $# -eq 0 ] && { echo; return; }
( shift; p "$@" ) | while read a ; do printf '%b' "$1$a\n$a\n"; done
}
p "$@"
将其称为此(如果您想要一行,请使用echo):
$ echo $(p a b c d e)
abcde bcde acde cde abde bde ade de abce bce ace ce abe be ae e abcd bcd acd cd abd bd ad d abc bc ac c ab b a<br>
注意:它适用于项目的“复杂”值,只是不要使用echo。
$ p " a b " "-c d-" "gg hh"
a b -c d-gg hh
-c d-gg hh
a b gg hh
gg hh
a b -c d-
-c d-
a b
并且,基于每个值的二进制表示的非递归选项(尽管较慢)。然而,它主要是bash,因为它广泛使用算术扩展。
#!/bin/bash
powerset(){
[[ $# -eq 0 ]] && { echo "Missing set of arguments" >&2; exit 2; }
local n ns; (( n=$#, ns=1<<n ))
for (( i=1; i<ns ; i++ )); do
a=''; # printf "%4.4s " "$i"
for (( j=1; j<=n; j++ )); do
(( i & 1<<(j-1) )) && a="${a}""${!j}" ;
done
echo "$a"
done
}
powerset "$@"
如果您需要编号结果,请删除a=''
后的注释符号(#)。
答案 2 :(得分:3)
假设你的数组是一组“简单”元素,有一个有趣的解决方案,涉及eval
动态生成的大括号表达式。
$ array=(a b c d)
$ printf -v br "{%s,}" "${array[@]}"
$ echo $br
{a,}{b,}{c,}{d,}
$ eval "printf '%s\\n' $br"
(它省略了空字符串,它将成为每个powerset的一部分,但你可以在之后手动添加。)
答案 3 :(得分:2)
使用eval
建立在早期答案的基础上eval echo $(sed 's/./{&,}/g' <<< "abcd") | tr ' ' '\n' | sort
会给你
a
ab
abc
abcd
abd
ac
acd
ad
b
bc
bcd
bd
c
cd
d