数组中的Bash检查元素用于另一个数组中的元素

时间:2021-03-02 15:42:25

I came over this cool Bash function for checking if an array contains an element:

我找到了这个很酷的Bash函数来检查一个数组是否包含一个元素:

CONTAINS_ELEMENT(){
  local e
  for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
  return 1
}

Here is an example of it's usage:

以下是它的用法示例:

if CONTAINS_ELEMENT $element "${array[@]}"; then
... 
fi

My question is this: Is there a way to rewrite this function so that it can check if any value within an array is equal to any value withing the other array, and not just check for one single value as it corrently does?

我的问题是:有没有办法重写这个函数,以便它可以检查数组中的任何值是否等于其他数组的任何值,而不只是检查一个单独的值,因为它正确吗?

3 个解决方案

#1


2  

CORRECTED#3

Try code bellow. ArrContains take two arguments, the name of the two arrays. It creates a temporary hash from lArr1 and then check if any elements of lArr2 is in the hash. This way the embedded for-loops can be avoided.

试试下面的代码。 ArrContains有两个参数,两个数组的名称。它从lArr1创建一个临时哈希,然后检查lArr2的任何元素是否在哈希中。这样可以避免嵌入式for循环。

#!/usr/bin/bash

ArrContains(){
  local lArr1 lArr2
  declare -A tmp
  eval lArr1=("\"\${$1[@]}\"")
  eval lArr2=("\"\${$2[@]}\"")
  for i in "${lArr1[@]}";{ ((++tmp['$i']));}
  for i in "${lArr2[@]}";{ [ -n "${tmp[$i]}" ] && return 0;}
  return 1
}

arr1=("a b" b c)
arr2=(x 'b c' e)
arr3=(q a\ b y)
ArrContains arr1 arr2 && echo Contains arr1 arr2
ArrContains arr1 arr3 && echo Contains arr1 arr3

Output:

Contains arr1 arr3

Other way could be to define some separation character and concatenate the first hash. Then search for matching the SEPitemSEP string.

其他方法可能是定义一些分离字符并连接第一个哈希。然后搜索匹配SEPitemSEP字符串。

ArrContainsRe(){
  local lArr1 lArr2 tmp
  eval lArr1=("\"\${$1[@]}\"")
  printf -v tmp ",%s" "${lArr1[@]}";
  tmp="$tmp,"
  eval lArr2=("\"\${$2[@]}\"")
  for i in "${lArr2[@]}";{ [[ $tmp =~ ,$i, ]] && return 0;}
  return 1
}
...
ArrContainsRe arr1 arr2 && echo ContainsRe arr1 arr2
ArrContainsRe arr1 arr3 && echo ContainsRe arr1 arr3

Output:

ContainsRe arr1 arr3

#2


0  

Looking at the links above I came over a solution that almost does what I need it to do, but not quite:

看看上面的链接,我找到了一个解决方案,它几乎完成了我需要它做的事情,但并不完全:

parameters=($1 $2 $3 $4)
arg1=(h help -h --help)

PARAMETERS(){
pr1=" $parameters[@]} "
for item in ${@:1}; do
  if [[ $pr1 =~ " $item " ]]; then
    return 0
  else
    return 1
  fi
done
}

if PARAMETERS "${arg1[@]}"; then
  echo "It works!"
else
  echo "Nope, still not working..."
fi

Now this code works when passing the parameter "h", but not when passing the other parameters in the array (-h --help help). Sorry if I am doing some stupid mistake here, I am somewhat of a nuub when it comes to bash scripting :)

现在这个代码在传递参数“h”时有效,但在传递数组中的其他参数时却没有(-h --help help)。对不起,如果我在这里做了一些愚蠢的错误,那么当涉及到bash脚本时,我有点像nuub :)

#3


-1  

This should do it:

这应该这样做:

any_overlap() {
    for e1 in "${array1[@]}"
    do
        for e2 in "${array2[@]}"
        do
            if [[ "$e1" = "$e2" ]]
            then
                return 0
            fi
        done
    done
    return 1
}

Test session:

$ array1=(foo bar baz) array2=(ban bat bar) && any_overlap; echo $?
0
$ array1=(foo bar baz) array2=(ban bat) && any_overlap; echo $?
1
$ array1=() array2=() && any_overlap; echo $?
1

Of course, there are faster ways to do it if the arrays are sorted or none of the array elements contain whitespace.

当然,也有更快的方式做到这一点,如果数组进行排序或没有数组元素包含空格。

#1


2  

CORRECTED#3

Try code bellow. ArrContains take two arguments, the name of the two arrays. It creates a temporary hash from lArr1 and then check if any elements of lArr2 is in the hash. This way the embedded for-loops can be avoided.

试试下面的代码。 ArrContains有两个参数,两个数组的名称。它从lArr1创建一个临时哈希,然后检查lArr2的任何元素是否在哈希中。这样可以避免嵌入式for循环。

#!/usr/bin/bash

ArrContains(){
  local lArr1 lArr2
  declare -A tmp
  eval lArr1=("\"\${$1[@]}\"")
  eval lArr2=("\"\${$2[@]}\"")
  for i in "${lArr1[@]}";{ ((++tmp['$i']));}
  for i in "${lArr2[@]}";{ [ -n "${tmp[$i]}" ] && return 0;}
  return 1
}

arr1=("a b" b c)
arr2=(x 'b c' e)
arr3=(q a\ b y)
ArrContains arr1 arr2 && echo Contains arr1 arr2
ArrContains arr1 arr3 && echo Contains arr1 arr3

Output:

Contains arr1 arr3

Other way could be to define some separation character and concatenate the first hash. Then search for matching the SEPitemSEP string.

其他方法可能是定义一些分离字符并连接第一个哈希。然后搜索匹配SEPitemSEP字符串。

ArrContainsRe(){
  local lArr1 lArr2 tmp
  eval lArr1=("\"\${$1[@]}\"")
  printf -v tmp ",%s" "${lArr1[@]}";
  tmp="$tmp,"
  eval lArr2=("\"\${$2[@]}\"")
  for i in "${lArr2[@]}";{ [[ $tmp =~ ,$i, ]] && return 0;}
  return 1
}
...
ArrContainsRe arr1 arr2 && echo ContainsRe arr1 arr2
ArrContainsRe arr1 arr3 && echo ContainsRe arr1 arr3

Output:

ContainsRe arr1 arr3

#2


0  

Looking at the links above I came over a solution that almost does what I need it to do, but not quite:

看看上面的链接,我找到了一个解决方案,它几乎完成了我需要它做的事情,但并不完全:

parameters=($1 $2 $3 $4)
arg1=(h help -h --help)

PARAMETERS(){
pr1=" $parameters[@]} "
for item in ${@:1}; do
  if [[ $pr1 =~ " $item " ]]; then
    return 0
  else
    return 1
  fi
done
}

if PARAMETERS "${arg1[@]}"; then
  echo "It works!"
else
  echo "Nope, still not working..."
fi

Now this code works when passing the parameter "h", but not when passing the other parameters in the array (-h --help help). Sorry if I am doing some stupid mistake here, I am somewhat of a nuub when it comes to bash scripting :)

现在这个代码在传递参数“h”时有效,但在传递数组中的其他参数时却没有(-h --help help)。对不起,如果我在这里做了一些愚蠢的错误,那么当涉及到bash脚本时,我有点像nuub :)

#3


-1  

This should do it:

这应该这样做:

any_overlap() {
    for e1 in "${array1[@]}"
    do
        for e2 in "${array2[@]}"
        do
            if [[ "$e1" = "$e2" ]]
            then
                return 0
            fi
        done
    done
    return 1
}

Test session:

$ array1=(foo bar baz) array2=(ban bat bar) && any_overlap; echo $?
0
$ array1=(foo bar baz) array2=(ban bat) && any_overlap; echo $?
1
$ array1=() array2=() && any_overlap; echo $?
1

Of course, there are faster ways to do it if the arrays are sorted or none of the array elements contain whitespace.

当然,也有更快的方式做到这一点,如果数组进行排序或没有数组元素包含空格。