2011-01-11 5 views
5

Например: У меня есть массивКак определить, что один массив является частью другого?

var src = new byte[] {1, 2, 3, 4, 5}; 
var tag = new byte[] {3, 4}; 

кто знает быстрый способ найти индекс массива тега? мне нужно что-то, как следующее:

int FindIndexOfSeq(byte[] src, byte[] sequence); 

последовательность может быть более чем один раз в ИПВ.

Решение: How to find index of sublist in list?

+1

можно дублировать http://stackoverflow.com/questions/3529727/how-to-find-index-of-sublist-in-list – nan

+2

Это не простая задача для эффективного решения. Наивный, простой в использовании поиск - это «O (nm)» наихудший случай. Вы можете улучшить это по существу (например, Boyer-Moore), но это непросто. http://en.wikipedia.org/wiki/String_searching_algorithm#Single_pattern_algorithms – Ani

+0

Только индекс первого вхождения? –

ответ

1
int FindIndexOfSeq<T>(byte[] src, byte[] tag) 
{ 
    Int32 tagCount = tag.Count();    

    // If `tag` is not empty and `src` contains `tag` 
    if (tagCount > 0 && src.Intersect(tag).Count() == tagCount) 
    { 
     // Find index of first element in `tag` 
     Int32 tagStartIndex = Array.IndexOf(src, tag.First()); 

     // Get the matching slice of `tag` from `src` 
     var newSrc = src.Skip(tagStartIndex).Take(tag.Count()).ToList(); 

     // Zip them together using their difference 
     var sum = Enumerable.Zip(tag, newSrc, (i1, i2) => Convert.ToInt32(i2 - i1)).Sum(); 

     // If total of their differences is zero, both sequences match 
     if (sum == 0) 
     { 
      // return starting index of `tag` in `src` 
      return tagStartIndex; 
     } 
    } 

    // return `Not Found` 
    return -1; 
} 
+0

Не было бы ошибкой, если src {1, 2, 3, 3, 4, 5} и тег {3, 4}? –

2

Вот один из способов до получения индекса

for (int i = 0; i < (src.Length - tag.Length); i++) 
{ 
    if (tag.SequenceEqual(src.Skip(i).Take(tag.Length))) 
     Console.WriteLine("It's at position " + i); 
} 

К сожалению, это очень медленно.

Если вы просто хотите знать, если все предметы в tag можно найти в src (в любом порядке), то

var src = new byte[] { 1, 2, 3, 4, 5 }; 
var tag = new byte[] { 4, 3 }; 

if (src.Intersect(tag).Count() == tag.Length) 
    Console.WriteLine("tag can be found in src!"); 
+0

Нет, мне нужно знать индекс, где начинается последовательность. –

+0

Умный достаточно. +1 – deadlock

+0

Jonas, в вашем примере у вас неправильный порядок байтов в массиве тега. –

2

лучшее, что вы можете получить это O (м), но я немного сложным реализация. Если вы удовлетворены решением, которое имеет O (m * n) в худшем случае, вы можете перейти к решению ниже. Если ваши последовательности упорядочены, и начальный элемент в массиве tag присутствует только один раз в src, это также приведет к O (m).

class Program 
{ 
    static void Main(string[] args) 
    { 
     var src = new byte[] { 1, 2, 3, 4, 5 }; 
     var tag = new byte[] { 3, 4 }; 
     var index = FindIndexOfSeq(src, tag); 
     Console.WriteLine(index); 
     Console.ReadLine(); 
    } 
    static int FindIndexOfSeq<T>(T[] src, T[] seq) 
    { 
     int index = -1; 
     for (int i = 0; i < src.Length - seq.Length + 1; i++) 
     { 
      bool foundSeq = true; 
      for (int j = 0; j < seq.Length; j++) 
      { 
       foundSeq = foundSeq && src[i + j].Equals(seq[j]); 
      } 
      if (foundSeq) 
      { 
       index = i; 
       break; 
      } 
     } 
     return index; 
    } 
} 

Я предположил, последовательность должны быть в таком порядке, и я только скомпилирован в Firefox, так что не уверен, если это работает :). Кроме того, я сделал его общим, поэтому он обрабатывает любые типы массивов, а не только байты.

UPDATE: Обновленный код компилируется и работает ... или мой простой тест работал.

+0

Вы можете * улучшить * O (nm) ', на самом деле это можно сделать в' O (n) '. Пример: Бойер-Мур. http://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm – Ani

+0

Вы правы ... Я обновил эту часть и включил простую программу. Кроме того, вы правы с O (n), но это похоже на гораздо более сложный алгоритм? Это быстрее на небольших наборах? Я думаю, что там есть небольшой компромисс. Если его последовательность похожа на ту, которую он предоставил, что приведет к O (n + m). –

+0

Да, я согласен с тем, что любой из них может быть переполнен для большинства распространенных применений. Но я все равно избавлюсь от «Лучшее, что вы можете получить, это O (m * n)»; это немного вводит в заблуждение. – Ani

Смежные вопросы