我在bash中有一个列表,其中可以包含重复的值。我想删除重复项并获取仅包含唯一值的列表。必须保留顺序,唯一值的最后一次出现是我希望保留的顺序。
例如,如果我有此列表:
A=( D B A C D )
我正在寻找:
result=( B A C D )
当数据是文件中的列表时,我已经看到了解决方案,但是我宁愿将列表保留在内存中,而不必跳过任何麻烦。
我认为我可以使用关联数组,并在列表中循环,将条目添加为数组中的键,然后将键转储到唯一列表中,但是我不是跨平台使用关联数组的专家吗?像许多C ++ STL容器一样对它们进行键值排序,或者它们保留插入顺序而不管键值如何?
尽管如此,我还是想避免依赖于关联数组,因为并非我可能需要在其上运行的所有系统都具有bash 4.x或更高版本...有些将是bash 3.x ...
任何帮助都会很棒。
答案 0 :(得分:3)
没有关联数组
您可以通过使用中间索引数组来保存A
中的唯一值来使用索引数组。这需要针对c[]
的每个元素,例如{p>
A
使用/输出示例
#!/bin/bash
declare -a result # declare result indexed array
declare -a c # declare temp intermediate indexed array
A=( D B A C D ) # original with duplicates
## loop decending over A, reset found flag, loop over c, if present continue,
# otherwise store A at index in c
for ((i = $((${#A[@]}-1)); i >= 0; i--)); do
found=0;
for j in ${c[@]}; do
[ "$j" = "${A[i]}" ] && { found=1; break; }
done
[ "$found" -eq '1' ] && continue
c[i]=${A[i]}
done
## loop over c testing if index for A exists, add from c to result
for ((i = 0; i < ${#A[@]}; i++)); do
[ "${c[i]}" ] && result+=(${c[i]})
done
declare -p result # output result
通过BASH_VERSION测试使用关联数组
您可以结合使用索引数组和关联数组来完成此操作,而仅通过每个数组即可。您使用关联数组$ bash lastuniqindexed.sh
declare -a result='([0]="B" [1]="A" [2]="C" [3]="D")'
并以B
的值作为键,并使用A
作为频率数组来指示是否已看到B
的元素。然后,您将A
的元素存储在临时索引数组A
中,以便可以将唯一值添加到c[]
中,以保留原始顺序。
您可以在开始时通过bash版本测试来解决关联数组功能是否存在
result
在不使用关联数组的情况下,随着数组大小的增加,对#!/bin/bash
case $BASH_VERSION in
## empty or beginning with 1, 2, 3
''|[123].*) echo "ERROR: Bash 4.0 needed" >&2
exit 1;;
esac
declare -A B # declare associative array
declare -a result # declare indexed array
A=( D B A C D ) # original with duplicates
## loop decending over A, if B[A] doesn't exist, set B[A]=1, store in c[]
for ((i = $((${#A[@]}-1)); i >= 0; i--)); do
[ -n "${B[${A[i]}]}" ] || { B[${A[i]}]=1; c[i]=${A[i]};}
done
## loop over c testing if index for A exists, add from c to result
for ((i = 0; i < ${#A[@]}; i++)); do
[ "${c[i]}" ] && result+=(${c[i]})
done
declare -p result # output result
中每个条目进行原始检查的嵌套循环的效率将大大降低。
使用/输出示例
c[]
仔细检查一下,如果还有其他问题,请告诉我。