如何使用数组搜索数组?

时间:2011-09-08 08:25:03

标签: c# .net vb.net arrays

我有2个字节的数组:

    Dim A() As Byte = {1, 2, 3, 4, 5, 6, 7, 8, 9}
    Dim B() As Byte = {5, 6, 7}

现在我想在A 中找到完整B的出现。我试过没有运气的Array.IndexOf(A,B)。是否有一种简单的方法可以按数组搜索数组而无需使用任何循环?

它应该以与B()中相同的顺序找到5,6,7的索引(位置)。 如果A()包含{1,2,3,4, 7,6,5 ,9},它应该返回false或-1,因为它们的顺序不同。

5 个答案:

答案 0 :(得分:4)

以下Linq语句将给出IEnumerable<int>包含b中a的位置(如果没有,则为空集):

Enumerable
    .Range( 0, 1 + a.Length - b.Length )
    .Where( i => a.Skip(i).Take(b.Length).SequenceEqual(b) );

我不知道如何翻译成VB.NET。

答案 1 :(得分:2)

这可能有用,但它是C#并使用循环:

private static int[] GetIndicesOf(byte[] needle, byte[] haystack)
{
    int[] foundIndices = new int[needle.Length];

    int found = 0;

    for (int i = 0; i < haystack.Length; i++)
    {

        if (needle[found] == haystack[i])
        {
            foundIndices[found++] = i;

            if (found == needle.Length)
                return foundIndices;
        }
        else
        {
            i -= found;   // Re-evaluate from the start of the found sentence + 1
            found = 0;    // Gap found, reset, maybe later in the haystack another occurrance of needle[0] is found
            continue;
        }
    }

    return null;            
}

使用输入测试:

Byte[] haystack = { 5, 6, 7, 8, 9, 0, 5, 6, 7 };
Byte[] needle = { 5, 6, 7 };
// Returns {0, 1, 2}

Byte[] haystack = { 5, 6, 0, 8, 9, 0, 5, 6, 7 };
Byte[] needle = { 5, 6, 7 };
// Returns {6, 7, 8}

Byte[] haystack = { 5, 6, 0, 7, 9, 0, 5, 6, 8 };
Byte[] needle = { 5, 6, 7 };
// Returns null

Byte[] haystack = { 1, 2, 1, 2, 2 };
Byte[] needle = { 1, 2, 2 };
// Returns {2, 3, 4}

Byte[] haystack = { 1, 2, 1, 2, 1, 2, 3 };
Byte[] needle = { 1, 2, 1, 2, 3 };
// Returns {2, 3, 4, 5, 6}

Byte[] haystack = { 1, 1, 1, 1, 2 };
Byte[] needle = { 1, 2 };
// Returns {3, 4}

但@spender的Linq实现看起来更好。 :-P

答案 2 :(得分:0)

如何创建一个方法:

  1. 将搜索到的列表的元素合并为一个字符串
  2. 包含列表元素以搜索一个字符串
  3. 在第一个字符串中查找第二个字符串的前置字符
  4. 像这样:

    public bool IsSubSetOf(IList<int> list1, IList<int> list2){
       var string1 = string.Join("", list1);
       var string2 = string.Join("", list2);
       return string1.Contains(string2);
    }
    

    未经测试......

答案 3 :(得分:0)

一般来说,解决这个问题的有效方法是KMP algorithm。快速谷歌搜索表明可以找到.NET实现here。它的实现伪代码可以从Wikipedia获得。

上面的一个链接中提供了一种低效但无害的代码编码方式,如下所示:

int[] T = new[]{1, 2, 3, 4, 5};
int[] P = new[]{3, 4};

for (int i = 0; i != T.Length; i++)
{
    int j = 0
    for (;i+j != T.Length && j != P.Length && T[i+j]==P[j]; j++);
    if (j == P.Length) return i;
}

答案 4 :(得分:0)

我的意思是:

public static int Search<T>(T[] space, T[] searched) {
  foreach (var e in Array.FindAll(space, e => e.Equals(searched[0]))) {
    var idx = Array.IndexOf(space, e);
    if (space.ArraySkip(idx).Take(searched.Length).SequenceEqual(searched))
      return idx;
  }
  return -1;
}

public static class Linqy {
  public static IEnumerable<T> ArraySkip<T>(this T[] array, int index) {
    for (int i = index;  i < array.Length; i++) {
      yield return array[i];
    }
  }
}

与往常一样,这取决于您的数据是否“足够好”,或者您将不得不求助于更复杂但更有效的算法。我介绍了一个arrayskip,因为Linq skip确实只假设IEnumerable接口,并且会枚举到索引。