user10889839
user10889839

Reputation:

How to compare two arrays of chars and see location?

Example: first sequence (A,B,C,D) second sequence (X,A,Z,A,B,C,D,E,A)

The first sequence is contained in the second sequence from position 4 because the letters A, B, C, D appear in exactly the same order as the first sequence

char[] firstSequence = new char[] { 'A', 'B', 'C', 'D'};
char[] secondSequence = new char[] {'X','A','Z','A','B','C','D','E','A'}

Upvotes: 0

Views: 135

Answers (4)

Caius Jard
Caius Jard

Reputation: 74605

Note; at the time this answer was written it wasn't clear that sequences under discussion were arrays of char. This answer gives a more general advice for collections of strings or complex types. For arrays of char a specific optimisation of not having a string.Join separator or using the string constructor that takes a char array, would be an option; other answers mention this so I won't repeat it here


Not really sure how you're storing your sequences but hopefully they're enumerable in which case:

string.Join(",", haystackCollection).Contains(string.Join(",", needleCollection));

I used comma as a separator but you should use a character that never occurs in the actual collections

More full example:

var haystackCollection = "XAZABCDEA".ToCharArray();
var needleCollection = "ABCD".ToCharArray();

bool result = string.Join(",", haystackCollection).Contains(string.Join(",", needleCollection));

This is only reliable if your collections are strings of identical length . It becomes unreliable if the haystack could contain strings of varying length because a haystack of {"AB","AC"} doesn't contain a needle of {"B","A"} but this method would report that it does.

You could fudge it to be better by putting separators at the start and end of each string join op:

string s = ",";
(s+string.Join(s, haystackCollection)+s).Contains(s+string.Join(",", needleCollection)+s);

But it might be better at this point to switch method entirely. Also if you want to know the index it occurs at it's a bit trickier using this string join method because you'd have to use IndexOf and then repeatedly subtract the lengths of each element plus the separator to get back to the index. You might be better off using loops instead:

int idx = 0;
while(idx < haystack.Length){
  if(haystack[idx] == needle[0]){
    int i = 1;
    while(haystack[idx+i] == needle[i] && i<needle.Length)
      i++;
    if(i == needle.Length)
      return idx; // you found the start of the needle
  }
  idx++;
}

In this latter method we start looking through the haystack trying to find the first element of the needle. If we find it, we start a loop that checks the rest of the needle. That loop only keeps gong while it finds needle entries in the haystack. If the loop stops early then the index variable i won't increment all the way up to the length of the needle array so we can conclude that if the variable i is indeed equal to the the Length of the needle, the needle was found at the position idx in the haystack

For this method to work out you really need your collections to be indexable by Integer rather than just enumerable, unless you want to get more convoluted. Remember that if you're using List instead of Array then it's Count rather than Length

Upvotes: 4

Ilia Afzali
Ilia Afzali

Reputation: 429

I'm not clear about your question , but if you mean that you want to find position of a string in another string you can use this :

  char[] firstSequence = new char[] { 'A', 'B', 'C', 'D'};
  char[] secondSequence = new char[] {'X','A','Z','A','B','C','D','E','A'}
  var firstString = new string(firstSequence);
  var secondString = new string(secondSequence);
  var positionIndex = secondString.IndexOf(fisrtString);

Upvotes: 1

Prasad Telkikar
Prasad Telkikar

Reputation: 16049

Convert your firstSequence and secondSequence into string and then use .Contains().

//Inputs
char[] firstSequence = new char[] { 'A', 'B', 'C', 'D'};
char[] secondSequence = new char[] {'X','A','Z','A','B','C','D','E','A'}

//Convert char array to string
string firstString = new string(firstSequence);
string secondString = new string(secondSequence);

//Use .Contains() to check string availability
bool isExist = secondString.Contains(firstString);

//Print message on console
Console.WriteLine(isExist ? "Sequence Exist" : "Sequence Not Exist");

//This will give you staring index of first string in second string i.e 3
//Next four will be your indexes that are 3, 4, 5, 6
if(isExist)
   {
       int startIndex = secondString.IndexOf(firstString);
       Console.WriteLine(string.Join(", ", Enumerable.Range(startIndex , firstString.Length)));
   }

Result:

Sequence Exist
3, 4, 5, 6

.NetFiddle

Upvotes: 2

Dmitrii Bychenko
Dmitrii Bychenko

Reputation: 186668

If you want just to test that firstSequence items appear somewhere within secondSequence in the same order that in firstSequence, e.g.

 {A, X, A, B, P, Q, D, A, C, D}
        ^  ^              ^  ^  
        A  B              C  D      

You can try Linq Aggregate: having item a and index within firstSequence we want to match, we can compute index we want to match with next item in secondSequence

Code:

using System.Linq;

... 

bool contains = secondSequence.Aggregate(0, 
   (index, a) => (index >= firstSequence.Length) || (firstSequence[index] != a)
     ? index                               // match completed or nothing to macth 
     : index + 1) >= firstSequence.Length; // match next item

Same idea, but different Aggregate if all firstSequence must appear without interuptions:

 {A, X, A, B, C, D, P, Q}
        ^  ^  ^  ^  
        A  B  C  D  

Code:

using System.Linq;

... 

bool contains = secondSequence
  .Aggregate(0, (index, a) =>
       index >= firstSequence.Length ? index // match found, do nothing
     : firstSequence[index] == a ? index + 1 // can we match next item?
     : firstSequence[0] == a ? 1             // restart and match the 1st item
     : 0)                                    // restart
    >= firstSequence.Length;                 // Have we match all items?  

Upvotes: 0

Related Questions