bash 比较两个已排序的数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17988915/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Comparing two sorted arrays
提问by Ozkan
Let's say I have the following 2 arrays. The arrays are always sorted alphabetically.
假设我有以下 2 个数组。数组总是按字母顺序排序。
arr1=(a b c)
arr2=(a b c d)
I have to compare these two arrays and if they are exactly the same then true must be returned.
我必须比较这两个数组,如果它们完全相同,则必须返回 true。
回答by marderh
I got a possible solution for you, using STDIN and diff:
我使用 STDIN 和 diff 为您提供了一个可能的解决方案:
#!/bin/bash
arr1=(a b c)
arr2=(a b c d)
diff=$(diff <(printf "%s\n" "${arr1[@]}") <(printf "%s\n" "${arr2[@]}"))
if [[ -z "$diff" ]]; then
echo "TRUE"
else
echo "FALSE"
fi
EDIT: A little explanation:
编辑:一点解释:
It makes a string out of your arrays and feeds them both to diff via STDIN. diff
either returns the difference or nothing, which i stuff into a variable and test with -z for content later.
它从您的数组中生成一个字符串,并通过 STDIN 将它们提供给 diff。diff
要么返回差异,要么不返回,我将其填充到变量中,然后用 -z 测试内容。
回答by fedorqui 'SO stop harming'
As "$*"
gets all the positional parameters as a single word, this can make it:
由于"$*"
得到所有的位置参数为一个单词,这可以使它:
[ "${arr1[*]}" == "${arr2[*]}" ] && echo "equal" || echo "distinct"
Note that the expression [ condition ] && echo "equal" || echo "distinct"
is equivalent to
请注意,该表达式[ condition ] && echo "equal" || echo "distinct"
等效于
if [ condition ]; then
echo "equal"
else
echo "distinct"
fi
Test
测试
$ arr1=(a b c)
$ arr2=(a b c d)
$ [ "${arr1[*]}" == "${arr2[*]}" ] && echo "equal" || echo "distinct"
distinct
$ arr2=(a b c)
$ [ "${arr1[*]}" == "${arr2[*]}" ] && echo "equal" || echo "distinct"
equal
It just works 100% when having elements without spaces (see discussion in comments).
当元素没有空格时,它只能 100% 工作(请参阅评论中的讨论)。
回答by mr.spuratic
The most robust way I can think of is:
我能想到的最强大的方法是:
- compare the array sizes first
- element by element compare
- 首先比较数组大小
- 逐个元素比较
So:
所以:
arr1=(1 2 3 )
arr2=(1 2 "3 4")
[ ${#arr1[*]} != ${#arr2[*]} ] && { echo arrays different size; exit 1; }
for ii in ${!arr1[*]}; do
[ "${arr1[$ii]}" == "${arr2[$ii]}" ] || { echo different element $ii; exit 1; }
done
echo arrays identical
exit 0
Constructions used are:
使用的结构是:
${#array[*]}
which returns the number of elements in an array${!array[*]}
which returns a list of indexes (rather than${array[*]}
which returns the elements)
${#array[*]}
它返回数组中的元素数${!array[*]}
它返回索引列表(而不是${array[*]}
返回元素)
The above should handle whitespace within array values, sparse arrays, and associative arrays (though it does not always catch different indexes in associative arrays, you'd need an extra test for that).
以上应该处理数组值、稀疏数组和关联数组中的空格(尽管它并不总是捕获关联数组中的不同索引,但您需要对此进行额外测试)。
回答by wget
For those of you who want a solution using a function instead of checking directly, here is a solution I wrote. The latter works with normal arrays, associative arrays and sparse arrays. But it requires at least Bash 4.3.
对于那些想要使用函数而不是直接检查的解决方案的人,这是我写的一个解决方案。后者适用于普通数组、关联数组和稀疏数组。但它至少需要 Bash 4.3。
This function is part of the lib I wrote. As a convention in my lib, I'm using return values and a retval
global argument for return statements more complex than a simple number. The same applies for errorWithLog
, which is just an echo on stderr
and logged as an error to the system logger if the latter is available.
这个函数是我写的lib的一部分。作为我的库中的约定,我使用返回值和retval
全局参数来处理比简单数字更复杂的返回语句。这同样适用于errorWithLog
,stderr
如果后者可用,它只是一个回显并作为错误记录到系统记录器中。
#-------------------------------------------------------------------------------
# I: - The array to compare tableA[@]
# - The second array tableB[@] against which to compare the first array
# P: Search if both arrays (all types) are equal
# NOTE: The tables must be passed *AS NAME* as myTable not as $myTable[@]
# nor ${myTable[@]} and requires Bash 4.3
# Inspired from http://stackoverflow.com/a/17990637/3514658
# and from http://stackoverflow.com/a/4017175/3514658
# O: - If both arrays are equal:
# - retval: true
# - return value for direct usage in a if statement: 0
# - If both arrays are not equal:
# - retval: false
# - return value for direct usage in a if statement: 1
#-------------------------------------------------------------------------------
function isArraysEqual() {
# Accessing by dereference using -n is new in Bash 4.3.
local -n arr1= 2>/dev/null
local -n arr2= 2>/dev/null
# If <Bash 4.3, need to use the following syntax, but checking the keys of
# associative arrays is not supported and, in that case, tables must be
# passed as names *WITH* elements i.e.: myTable[@]
# local -a arr1=("${!1}")
# local -a arr2=("${!2}")
if [ $? -ne 0 ]; then
errorWithLog "isArraysEqual() accessing using dereference with -n"\
"needs at least Bash 4.3. Arrays reported as different."
retval=false
return 1
fi
# Check size first. This is way faster than checking each item over
# iteration.
if [ ${#arr1[@]} != ${#arr2[@]} ]; then
retval=false
return 1
fi
# The ! expands to a list of array keys. For normal arrays, not associative
# arrays, this gives a list of index values starting from 0.
local -a arr1Keys=("${!arr1[@]}")
local -a arr2Keys=("${!arr2[@]}")
for (( i = 0; i < ${#arr1[@]}; i += 1 )); do
key=${arr1Keys[$i]}
# Check if the values are the same. If the key does not exist in arr2
# and the key does exist but is null in arr1, the values are NOT
# considered different. This is why checking keys is mandatory.
if [ "${arr1[$key]}" != "${arr2[$key]}" ]; then
retval=false
return 1
fi
# Check if keys are the same. This is needed for associative arrays.
if [ "${arr1Keys[$i]}" != "${arr2Keys[$i]}" ]; then
retval=false
return 1
fi
done
retval=true
return 0
}
Usage examples:
用法示例:
declare -A table1=([hello]=world [ab]=cd)
declare -A table2=([hello]=world [ab]=cd)
if isArraysEqual table1[@] table2[@]; then
echo "yes"
else
echo "no"
fi
Gives yes
.
给yes
。
declare -A table1=([hello]=world [ab]=cd)
declare -A table2=([hello]=world [ab]=cde)
if isArraysEqual table1 table2; then
echo "yes"
else
echo "no"
fi
Gives no
.
给no
。
declare -A table1=([hello]=world [abhe]=ce)
declare -A table2=([hello]=world [ab he]=ce)
if isArraysEqual table1 table2; then
echo "yes"
else
echo "no"
fi
Gives no
.
给no
。
table1=(1 2 3 4)
table2=(1 2 "3 4")
if isArraysEqual table1 table2; then
echo "yes"
else
echo "no"
fi
Gives no
.
给no
。