how to compare if two arrays share at least one element

Hello,
I’m new in arduino.

I have two arrays and would like to return the first element shared.

I used this setup program with a function, but it does’nt work as I guess :(.

Program:

/////////////////////////////////////////////////////////////////////////////
int tag_test[3] = {1, 2, 3};
int myArray_test = {4, 5, 6, 7, 8, 9, 2};
int tag_found = 0;

void setup()
{
Serial.begin(9600);

tag_found = findTag(myArray_test, tag_test);
Serial.print(“tag_found: “);
Serial.println(tag_found);
Serial.println(”\n\n\n”);

}

int findTag(int TagList, int tag_func)
{
int i=0;
int j=0;
while(TagList != tag_func[j] && i<sizeof(TagList)/2)

  • {*
  • Serial.print(“TagList[”);*
  • Serial.print(i);*
  • Serial.print("]: “);*
    _ Serial.println(TagList*);_
    Serial.print(“tag_func[”);
    _
    Serial.print(j);_
    _
    Serial.print(”]: “);_
    Serial.println(tag_func[j]);
    _
    i = i+1;_
    while(TagList != tag_func[j] && j<sizeof(tag_func)/2)
    _ {
    Serial.print(“TagList[”);
    Serial.print(i);
    Serial.print(”]: “);
    Serial.println(TagList);_

    Serial.print(“tag_func[”);
    _ Serial.print(j);
    Serial.print(”]: ");_

    Serial.println(tag_func[j]);
    _ j=j+1;
    }
    }_

    _return TagList;
    }
    void loop()
    {*_

}
//////////////////////////////////////////////////////////////
when executed, I get the print screen in attachement.
Why my program returns 5!
normally it has to run and reurn 2 after many iterations :frowning:
Thanks for help.
Capture array comp.JPG

Please edit your post to add code tags, as described in How to use this forum.

Hello jremington,

Thanks for your quick reply. I m new and this is my first post!

How to edit the post? I do not find this menu : "How to use this forum"

Regards,

Here's the link to How to Use this Forum. Pay particular attention to Item7 about the use of code tags.

https://forum.arduino.cc/index.php?topic=148850.0

To edit your post there is a pull down menu at the lower right of your posting with edit and modify available.

Code edited:

int tag_test[3] = {1, 2, 3};
int myArray_test[] = {4, 5, 6, 7, 8, 9, 2};
int tag_found = 0;

void setup()
{
Serial.begin(9600);



tag_found = findTag(myArray_test, tag_test);
Serial.print("tag_found: ");
Serial.println(tag_found);
Serial.println("\n\n\n");


}

int findTag(int TagList[], int tag_func[])
{
int i=0;
int j=0;
  while(TagList[i] != tag_func[j] && i<sizeof(TagList)/2)
  {
  Serial.print("TagList[");
  Serial.print(i);
  Serial.print("]: ");
  Serial.println(TagList[i]);
  Serial.print("tag_func[");
  Serial.print(j);
  Serial.print("]: ");
  Serial.println(tag_func[j]);
  i = i+1;
    while(TagList[i] != tag_func[j] && j<sizeof(tag_func)/2)
    {
    Serial.print("TagList[");
    Serial.print(i);
    Serial.print("]: ");
    Serial.println(TagList[i]);
    Serial.print("tag_func[");
    Serial.print(j);
    Serial.print("]: ");
    Serial.println(tag_func[j]);
    j=j+1;
    }
  }
return TagList[i];
}


void loop() 
{
  
}

The problem is that once you an array is passed to a function, it becomes a pointer. So sizeof() is meaningless.

The following code should work as per your requirement.

template<int fs, int ss> int FindTag(int(&first)[fs], int(&second)[ss])
{
  for (int ele : first) {
    for (int comp : second) {
      if (ele == comp) {
        return ele;
      }
    } 
  }
  return -1;
}

void setup() 
{
  Serial.begin(9600);
  int tag_test[3] = {1, 2, 3};
  int myArray_test[] = {4, 5, 6, 7, 8, 9, 2};
  int result = FindTag(tag_test, myArray_test);
  Serial.println(result);
}

void loop() 
{
  // put your main code here, to run repeatedly:
}

If the search space is large, it’ll be much faster to first sort the array you’re going to search through, so you can use binary search:

[color=#5e6d03]template[/color] [color=#434f54]<[/color][b][color=#d35400]size_t[/color][/b] [color=#000000]Na[/color][color=#434f54],[/color] [b][color=#d35400]size_t[/color][/b] [color=#000000]Nb[/color][color=#434f54]>[/color] [color=#00979c]int[/color] [color=#000000]first_intersect_impl[/color][color=#000000]([/color][color=#00979c]int[/color] [color=#000000]([/color][color=#434f54]&[/color][color=#000000]a[/color][color=#000000])[/color][color=#000000][[/color][color=#000000]Na[/color][color=#000000]][/color][color=#434f54],[/color] [color=#00979c]int[/color] [color=#000000]([/color][color=#434f54]&[/color][color=#000000]b[/color][color=#000000])[/color][color=#000000][[/color][color=#000000]Nb[/color][color=#000000]][/color][color=#000000])[/color] [color=#000000]{[/color]
  [color=#000000]std[/color][color=#434f54]:[/color][color=#434f54]:[/color][color=#000000]sort[/color][color=#000000]([/color][color=#000000]std[/color][color=#434f54]:[/color][color=#434f54]:[/color][color=#d35400]begin[/color][color=#000000]([/color][color=#000000]a[/color][color=#000000])[/color][color=#434f54],[/color] [color=#000000]std[/color][color=#434f54]:[/color][color=#434f54]:[/color][color=#d35400]end[/color][color=#000000]([/color][color=#000000]a[/color][color=#000000])[/color][color=#000000])[/color][color=#000000];[/color]
  [color=#5e6d03]for[/color] [color=#000000]([/color][color=#00979c]int[/color] [color=#000000]element[/color] [color=#434f54]:[/color] [color=#000000]b[/color][color=#000000])[/color]
      [color=#5e6d03]if[/color] [color=#000000]([/color][color=#000000]std[/color][color=#434f54]:[/color][color=#434f54]:[/color][color=#000000]binary_search[/color][color=#000000]([/color][color=#000000]std[/color][color=#434f54]:[/color][color=#434f54]:[/color][color=#d35400]begin[/color][color=#000000]([/color][color=#000000]a[/color][color=#000000])[/color][color=#434f54],[/color] [color=#000000]std[/color][color=#434f54]:[/color][color=#434f54]:[/color][color=#d35400]end[/color][color=#000000]([/color][color=#000000]a[/color][color=#000000])[/color][color=#434f54],[/color] [color=#000000]element[/color][color=#000000])[/color][color=#000000])[/color]
          [color=#5e6d03]return[/color] [color=#000000]element[/color][color=#000000];[/color]
  [color=#5e6d03]return[/color] [color=#434f54]-[/color][color=#000000]1[/color][color=#000000];[/color]
[color=#000000]}[/color]
#include <Arduino_Helpers.h> // https://github.com/tttapa/Arduino-Helpers
#include <AH/STL/algorithm>
#include <AH/STL/iterator>

// a must be smaller than b
template <size_t Na, size_t Nb> int first_intersect_impl(int (&a)[Na], int (&b)[Nb]) {
  std::sort(std::begin(a), std::end(a));
  for (int element : b)
      if (std::binary_search(std::begin(a), std::end(a), element))
          return element;
  return -1;
}

template <size_t Na, size_t Nb> int first_intersect(int (&a)[Na], int (&b)[Nb]) {
  if (Na <= Nb) return first_intersect_impl(a, b);
  else          return first_intersect_impl(b, a);  
}

void setup() {
  Serial.begin(115200);
  while (!Serial);
  int tag_test[] = {1, 2, 3};
  int myArray_test[] = {4, 5, 6, 7, 8, 9, 2};
  int tag_found = first_intersect(tag_test, myArray_test);
  Serial.println(tag_found);
}

void loop() {}

You can limit the sorting time overhead by only sorting only once (or only when you change it).
Also, don’t assume binary search will be faster, measure it if it’s important. For small arrays like in your example, it’ll most likely be slower.

Pieter

I think templates might be hard for a beginner who says he’s new to Arduino. Perhaps something a little simplier:

#define ELEMENTS(x) (sizeof(x) / sizeof(x[0]))  // type-less way to count elements

int tagTest[3] = {1, 2, 3};
int myArray[]  = {4, 5, 6, 7, 8, 9, 2};
int tag_found  = 0;

void setup()
{
  Serial.begin(9600);

  tag_found = findTag();        // Why pass then if they are globals?
  Serial.print("tag_found: ");
  Serial.println(tag_found);
  Serial.println("\n\n\n");
}

int findTag()
{
  int i = 0;
  int j = 0;
  for (i = 0; i < ELEMENTS(tagTest); i++) {
    for (j = 0; j < ELEMENTS(myArray); j++) {
      if (tagTest[i] == myArray[j]) {
        Serial.print("Match at: tagTest[");
        Serial.print(i);
        Serial.print("] = ");
        Serial.print(tagTest[i]);
        Serial.print(" = myArray[");
        Serial.print(j);
        Serial.println("]");
        return tagTest[i];
      }
    }
  }
}


void loop()
{

}

econjack:
I think templates might be hard for a beginner who says he’s new to Arduino. Perhaps something a little simplier:

The alternatives of passing data around using global arrays and having manual loop indices are worse than using templates in my eyes. Templates are not harder than the sizeof macro you’re using.
Fully understanding templates is difficult, but just using them to determine the size of an array is simple to understand and pretty foolproof (unlike calling sizeof on an array parameter, which will just give the wrong result without any warning).
There’s simply no other safe and convenient way to pass arrays to functions.

Explanation

template <size_t Na, size_t Nb>

The “template” keyword here means that the function depends on parameters that have to be determined at compile-time (normal parameters can be changed at run-time, template parameters cannot).
Normal parameters go between parentheses ( ), template parameters go between angled brackets < >.
There are two template parameters in this example: their type is size_t (size type), and their names are “Na” and “Nb”.
Na will later be used for the size of array “a”, and Nb will be used for the size of array “b”.

int first_intersectl(int (&a)[Na], int (&b)[Nb])

The first normal parameter “a” is a reference to an array of integers of size Na, second parameter “b” is a reference to an array of integers of size Nb.
References are used, because copying the arrays would be costly and unnecessary*.
Parameters that are passed by reference are declared using an ampersand (&).
Note how the template parameters Na and Nb are used to specify the type of the normal parameters (the size of an array is part of its type).

When calling the function, the compiler will fill in the sizes Na and Nb for you.


⁽*⁾ Because raw C-arrays are somewhat special, passing them by value would also be much more involved than passing them by reference. Anyway, passing them by reference is definitely the easiest and the most efficient option.

PieterP:

⁽*⁾ Because raw C-arrays are somewhat special, passing them by value would also be much more involved than passing them by reference. Anyway, passing them by reference is definitely the easiest and the most efficient option.

I would argue the opposite, the compiler manages passing by reference by just passing the pointer by value underhood. So, passing by reference is not more efficient, since the compiler needs to check for NULL too.

I agree that using macro to determine array length is bad. OP would face the same problem if he use the macro on a function argument.

arduino_new:
I would argue the opposite, the compiler manages passing by reference by just passing the pointer by value underhood. So, passing by reference is not more efficient, since the compiler needs to check for NULL too.

I mean passing the array by value, i.e. copying the entire array. It is more involved because you would have to wrap them in a struct like std::array does.
Using a reference is cheaper than copying the array, not cheaper than passing the array by pointer (which is indeed the default).

By the way, the compiler doesn’t check for NULL in either case.

PieterP: I mean passing the array by value, i.e. copying the entire array. It is more involved because you would have to wrap them in a struct like std::array does. Using a reference is cheaper than copying the array, not cheaper than passing the array by pointer (which is indeed the default).

By the way, the compiler doesn't check for NULL in either case.

Can you give an example where the function make a copy of an entire array when you pass it an array? Now when you pass a variable by reference, the compiler make sure it's not NULL right?

arduino_new:
Can you give an example where the function make a copy of an entire array when you pass it an array?
Now when you pass a variable by reference, the compiler make sure it’s not NULL right?

That’s the point I was trying to make, you cannot pass an array by value unless you wrap it:

[color=#5e6d03]template[/color] [color=#434f54]<[/color][color=#00979c]class[/color] [color=#000000]T[/color][color=#434f54],[/color] [b][color=#d35400]size_t[/color][/b] [color=#000000]N[/color][color=#434f54]>[/color] [color=#00979c]struct[/color] [color=#00979c]array[/color] [color=#000000]{[/color] [color=#000000]T[/color] [color=#000000]data[/color][color=#000000][[/color][color=#000000]N[/color][color=#000000]][/color][color=#000000];[/color] [color=#000000]}[/color][color=#000000];[/color]

[color=#5e6d03]template[/color] [color=#434f54]<[/color][b][color=#d35400]size_t[/color][/b] [color=#000000]N[/color][color=#434f54]>[/color][color=#00979c]void[/color] [color=#000000]f[/color][color=#000000]([/color][color=#00979c]array[/color][color=#434f54]<[/color][color=#00979c]int[/color][color=#434f54],[/color] [color=#000000]N[/color][color=#434f54]>[/color] [color=#000000]a[/color][color=#000000])[/color] [color=#000000]{[/color][color=#000000]}[/color]

[color=#00979c]void[/color] [color=#000000]foo[/color][color=#000000]([/color][color=#000000])[/color] [color=#000000]{[/color]
  [color=#00979c]array[/color][color=#434f54]<[/color][color=#00979c]int[/color][color=#434f54],[/color] [color=#000000]3[/color][color=#434f54]>[/color] [color=#000000]a[/color] [color=#434f54]=[/color] [color=#000000]{[/color][color=#000000]1[/color][color=#434f54],[/color] [color=#000000]2[/color][color=#434f54],[/color] [color=#000000]3[/color][color=#000000]}[/color][color=#000000];[/color]
  [color=#000000]f[/color][color=#000000]([/color][color=#000000]a[/color][color=#000000])[/color][color=#000000];[/color]
[color=#000000]}[/color]

A reference to a variable cannot be null. The only way to get a null reference is if you create it yourself (using *nullptr, for example). The compiler doesn’t insert any null checks. The responsibility is yours, because you dereferenced a null pointer.

Perhaps I misunderstood your assertion earlier. However, consider the following cases:

int Geta(int *a);
int Getb(int &a);
int Getc(int *arr);
int Getd(int (&arr)[5]);

//calling variable
int num;
Geta(&num); //pass by value as pointer
Getb(num);//pass by reference

//calling array
int array[5];
Getc(array); //pass array by value
Getd(array); //pass array by reference.

Were you arguing that Getb() and Getd() - both are passing by reference - would be more efficience than Geta() and Getc()?

arduino_new: Were you arguing that Getb() and Getd() - both are passing by reference - would be more efficience than Geta() and Getc()?

No, the calling conventions are exactly the same, all of them pass a pointer under the hood. Just the syntax and usage are different for pointers and references.

I was talking about passing an array by value/b versus passing an array by reference (or pointer for that matter).

Nice discussion for CS 201. But, wonder what OP gets out of it.

PieterP: I was talking about passing an array by value/b versus passing an array by reference (or pointer for that matter). [/quote] But we already established that array cannot be passed by value ie, be deep copied. Also, I think containers are irrelevant in this category. Since one could just modify the copy constructor to never do deep copy.

arduino_new: But we already established that array cannot be passed by value ie, be deep copied.

Only C-arrays cannot be deep-copied. C++ arrays can. I showed you an example that does that, and std:array behaves equivalently.

arduino_new: Also, I think containers are irrelevant in this category. Since one could just modify the copy constructor to never do deep copy.

std::array is the preferred array type in C++, exactly because the C-array semantics are so confusing, so I don't see how that would be irrelevant.

PieterP:
Only C-arrays cannot be deep-copied. C++ arrays can. I showed you an example that does that, and std:array behaves equivalently.std::array is the preferred array type in C++, exactly because the C-array semantics are so confusing, so I don’t see how that would be irrelevant.

Alright, I didn’t realize there’s a separate between C array and C++ array. I don’t agree with that separation and std::array<> is not C++ array. You can just easily implement std::array<> to wrap C array too (excluding move semantic). But let’s wrap this up.

PieterP: Fully understanding templates is difficult, but just using them to determine the size of an array is simple to understand and pretty foolproof (unlike calling sizeof on an array parameter, which will just give the wrong result without any warning). There's simply no other safe and convenient way to pass arrays to functions.

Really? You think that your discussion was easier to understand for a beginner than two for loops? Also, please give an example of how sizeof on an array doesn't work. Also, please explain why simply passing the reference for an array isn't safe and convenient.