C# 如何确定一个数组是另一个数组的一部分?

C# 如何确定一个数组是另一个数组的一部分?,c#,.net,arrays,C#,.net,Arrays,例如:我有一个数组 var src = new byte[] {1, 2, 3, 4, 5}; var tag = new byte[] {3, 4}; 谁知道快速查找标签数组索引的方法? 我需要的东西如下: int FindIndexOfSeq(byte[] src, byte[] sequence); 一个序列在src中可以出现多次 解决方案:这里有一种获取索引的方法 for (int i = 0; i < (src.Length - tag.Length); i++ ) {

例如:我有一个数组

var src = new byte[] {1, 2, 3, 4, 5};
var tag = new byte[] {3, 4};
谁知道快速查找标签数组索引的方法? 我需要的东西如下:

int FindIndexOfSeq(byte[] src, byte[] sequence);
一个序列在src中可以出现多次


解决方案:

这里有一种获取索引的方法

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);
}
您可以得到的最好结果是O(m),但我认为实现有点复杂。如果你对一个以O(m*n)为最坏情况的解决方案感到满意,你可以使用下面的解决方案。如果序列已排序,且
标记中的起始项在
src
中仅出现一次,则这也将导致O(m)

类程序
{
静态void Main(字符串[]参数)
{
var src=新字节[]{1,2,3,4,5};
var tag=新字节[]{3,4};
var指数=FindIndexOfSeq(src,tag);
控制台写入线(索引);
Console.ReadLine();
}
静态int FindIndexOfSeq(T[]src,T[]seq)
{
int指数=-1;
对于(int i=0;i
我假设序列必须按照这个顺序,并且我只在firefox中编译了它,所以不确定它是否有效:)。此外,我将其设置为通用的,这样它可以处理任何类型的数组,而不仅仅是字节

更新:更新后的代码编译并运行。。。或者我的简单测试成功了。

int FindIndexOfSeq(byte[]src,byte[]tag)
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;
}
{ Int32 tagCount=tag.Count(); //如果'tag'不为空且'src'包含'tag'` if(tagCount>0&&src.Intersect(tag.Count()==tagCount) { //查找`标记中第一个元素的索引` Int32 tagStartIndex=Array.IndexOf(src,tag.First()); //从'src'获取'tag'的匹配片段` var newSrc=src.Skip(tagStartIndex).Take(tag.Count()).ToList(); //使用它们的差异将它们压缩在一起 var sum=Enumerable.Zip(tag,newSrc,(i1,i2)=>Convert.ToInt32(i2-i1)).sum(); //如果它们的差异总和为零,则两个序列匹配 如果(总和=0) { //返回`src中`tag`的起始索引` 返回tagStartIndex; } } //return`找不到` 返回-1; }
此任务相当于在字符串中搜索子字符串。为此,您可以使用任何KMP算法以获得更好的性能: 找到了解决方案


不,我需要知道序列开始的索引。Jonas,在您的示例中,标记数组中的字节顺序错误。如果
标记包含重复元素,我认为这不起作用。或者即使
src
这样做了。@Dmitry。。。他这样做是为了告诉你,如果他发现所有元素都不考虑顺序,他会返回true。@Jon我想不会,但这取决于Dmitry想如何处理这些情况。可能重复这不是一个容易有效解决的问题。最糟糕的情况是
O(nm)
。你可以在这方面做很大的改进(例如Boyer Moore),但这并不容易。只有第一次出现的指数?Ani是完全正确的,我提供的解决方案是O(nm)的任何类型的序列。。。但是如果序列是有序的,并且每个序列中的项只出现一次,那么我的解将得到O(n)。您需要什么取决于您的需求,如果您有大数据集等。如果常数因子较高,对于小数据集,O(n)解决方案可能比O(nm)慢。您可以改进
O(nm)
,事实上可以在
O(n)
中实现。例子:博耶·摩尔。你是对的。。。我更新了那个部分,包括了一个简单的程序。同样,O(n)是正确的,但这似乎是一个更复杂的算法?小布景快吗?我认为这是一个小交易。如果他的序列看起来像他提供的那样,将导致O(n+m)。是的,我同意实现其中任何一个对于大多数常见用途来说都可能是过分的。但我仍然会摆脱“你能得到的最好的是O(m*n)”;这有点误导。
foundSeq=true&&
true&&
no op吗?我本想写
foundSeq&&…
,但在这种情况下,这没关系。如果src是{1,2,3,3,4,5}而tag是{3,4},这不会出错吗?这个问题没有公认的答案。你喜欢哪一个?
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;
    }
}
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;
}