Sign up ×
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other. Join them; it only takes a minute:

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

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?

share|improve this question
    
Not correct! Try "${@:2}". – TrueY Jun 11 '13 at 10:51
    
Very similar to array intersection questions 1 and 2. – l0b0 Jun 11 '13 at 10:59
2  
To show the question was solved, tick one of the answers as "accepted". – fedorqui Jun 11 '13 at 13:03

3 Answers 3

up vote 2 down vote accepted

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.

#!/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.

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
share|improve this answer
    
@l0b0: You are right! The first function handled it badly. I corrected. Thanks! – TrueY Jun 11 '13 at 11:34
    
@l0b0: I just wanted to upvote your last comment, but it was removed... ;) Anyway thanks for them! – TrueY Jun 11 '13 at 11:47
    
This fails when I try it. It returns nothing, no matter what. – Dan-Simon Myrland Jun 11 '13 at 12:03
    
@Dan-SimonMyrland: Sorry, I overreacted my last correction! Bad single quotation marks were removed. Corrected! Thanks! – TrueY Jun 11 '13 at 12:39
    
This works! Thanks :D – Dan-Simon Myrland Jun 11 '13 at 13:00

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 :)

share|improve this answer
    
One syntax problem: pr1=" $parameters[@]} " might be pr1=" ${parameters[@]} ". But I may suggest to use local pr1=.... And a semantics problem: the if will return in the first loop in PARAMETERS. I assume the else part is not needed. – TrueY Jun 11 '13 at 12:47
    
Ok, your own solution proved a better way of solving my problem. Thanks again for your help! – Dan-Simon Myrland Jun 11 '13 at 13:02

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.

share|improve this answer
    
How would you take two arrays as parameters? It's not possible. – l0b0 Jun 11 '13 at 11:02
    
You can take the size of the first array as the first parameter :-) – choroba Jun 11 '13 at 11:02
    
"Also, if the first two elements in the respective arrays are different, it returns 0." What do you mean? I just tested it, and it works fine. – l0b0 Jun 11 '13 at 11:03
    
Can you please delete the comment in that case? It's just noise now :/ – l0b0 Jun 11 '13 at 11:22
1  
@choroba: Exactly the same cannot be implemented. Some trick has to be added as bash cannot pass two separate arrays to a function. – TrueY Jun 11 '13 at 13:47

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.