给定两个数组作为参数(x和y)并找到x中第一次出现y的起始索引。我想知道最简单或最快的实现是什么。
示例:
when x = {1,2,4,2,3,4,5,6}
y = {2,3}
result
starting index should be 3
更新:由于我的代码错误,我将其从问题中移除。
答案 0 :(得分:6)
最简单的写作?
return (from i in Enumerable.Range(0, 1 + x.Length - y.Length)
where x.Skip(i).Take(y.Length).SequenceEqual(y)
select (int?)i).FirstOrDefault().GetValueOrDefault(-1);
当然不是那么有效......有点像它:
private static bool IsSubArrayEqual(int[] x, int[] y, int start) {
for (int i = 0; i < y.Length; i++) {
if (x[start++] != y[i]) return false;
}
return true;
}
public static int StartingIndex(this int[] x, int[] y) {
int max = 1 + x.Length - y.Length;
for(int i = 0 ; i < max ; i++) {
if(IsSubArrayEqual(x,y,i)) return i;
}
return -1;
}
答案 1 :(得分:5)
这是一个简单(但相当有效)的实现,它可以找到数组的所有出现,而不仅仅是第一个:
static class ArrayExtensions {
public static IEnumerable<int> StartingIndex(this int[] x, int[] y) {
IEnumerable<int> index = Enumerable.Range(0, x.Length - y.Length + 1);
for (int i = 0; i < y.Length; i++) {
index = index.Where(n => x[n + i] == y[i]).ToArray();
}
return index;
}
}
示例:
int[] x = { 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4 };
int[] y = { 2, 3 };
foreach (int i in x.StartingIndex(y)) {
Console.WriteLine(i);
}
输出:
1
5
9
该方法首先循环遍历x
数组,以查找y
数组中第一项的所有出现,并将其索引放在index
数组中。然后继续通过检查哪些匹配y
数组中的第二项来减少匹配。检查y
数组中的所有项目后,index
数组仅包含完整匹配。
编辑:
另一种实现方式是从循环语句中删除ToArray
调用,只需:
index = index.Where(n => x[n + i] == y[i]);
这将完全改变方法的工作方式。它不是逐级循环遍历项目,而是返回具有嵌套表达式的枚举器,将搜索推迟到迭代枚举器的时间。这意味着如果你想要,你只能获得第一场比赛:
int index = x.StartingIndex(y).First();
这不会找到所有匹配项,然后返回第一个匹配项,只搜索到第一个匹配项,然后返回它。
答案 2 :(得分:3)
最简单的方法可能就是:
public static class ArrayExtensions
{
private static bool isMatch(int[] x, int[] y, int index)
{
for (int j = 0; j < y.Length; ++j)
if (x[j + index] != y[j]) return false;
return true;
}
public static int IndexOf(this int[] x, int[] y)
{
for (int i = 0; i < x.Length - y.Length + 1; ++i)
if (isMatch(x, y, i)) return i;
return -1;
}
}
但这绝对不是最快的方式。
答案 3 :(得分:2)
这与在字符串中查找子字符串的问题基本相同。假设你在“快速的棕色狐狸跳过懒狗”中寻找“狐狸”。在这种情况下,天真的字符串匹配算法非常好。如果您正在寻找“bananananananananananananananana”一百万个字符的字符串,它是形式的内部“banananananabanananabananabananabanananananbananana ......”那么天真的串匹配算法的可怕的 - 远远快的结果可以通过使用获得更复杂和复杂的字符串匹配算法。基本上,朴素算法是O(nm),其中n和m是源和搜索字符串的长度。有O(n + m)算法,但它们要复杂得多。
您能告诉我们您正在搜索的数据的更多信息吗?它有多大,多余,搜索数组有多长,以及匹配不良的可能性是多少?
答案 4 :(得分:2)
这基于Mark Gravell's answer,但我将其设为通用,并添加了一些简单的边界检查以防止异常被抛出
private static bool IsSubArrayEqual<T>(T[] source, T[] compare, int start) where T:IEquatable<T>
{
if (compare.Length > source.Length - start)
{
//If the compare string is shorter than the test area it is not a match.
return false;
}
for (int i = 0; i < compare.Length; i++)
{
if (source[start++].Equals(compare[i]) == false) return false;
}
return true;
}
可以通过实施Boyer-Moore进一步改进,但对于简短模式,它可以正常工作。
答案 5 :(得分:1)
我发现以下几行更直观,但这可能是一种品味问题。
public static class ArrayExtensions
{
public static int StartingIndex(this int[] x, int[] y)
{
var xIndex = 0;
while(xIndex < x.length)
{
var found = xIndex;
var yIndex = 0;
while(yIndex < y.length && xIndex < x.length && x[xIndex] == y[yIndex])
{
xIndex++;
yIndex++;
}
if(yIndex == y.length-1)
{
return found;
}
xIndex = found + 1;
}
return -1;
}
}
此代码还解决了我认为您的实施可能遇到的问题,例如x = {3,3,7},y = {3,7}。我认为你的代码会发生什么,它匹配第一个数字,然后在第二个数字上重置自己,但在第三个数字上再次开始匹配,而不是在它开始匹配之后回到索引。可能会遗漏一些东西,但这绝对值得考虑,应该可以在代码中轻松修复。
答案 6 :(得分:0)
//this is the best in C#
//bool contains(array,subarray)
// when find (subarray[0])
// while subarray[next] IS OK
// subarray.end then Return True
public static bool ContainSubArray<T>(T[] findIn, out int found_index,
params T[]toFind)
{
found_index = -1;
if (toFind.Length < findIn.Length)
{
int index = 0;
Func<int, bool> NextOk = (i) =>
{
if(index < findIn.Length-1)
return findIn[++index].Equals(toFind[i]);
return false;
};
//----------
int n=0;
for (; index < findIn.Length; index++)
{
if (findIn[index].Equals(toFind[0]))
{
found_index=index;n=1;
while (n < toFind.Length && NextOk(n))
n++;
}
if (n == toFind.Length)
{
return true;
}
}
}
return false;
}
答案 7 :(得分:0)
using System;
using System.Linq;
public class Test
{
public static void Main()
{
int[] x = {1,2,4,2,3,4,5,6};
int[] y = {2,3};
int? index = null;
for(int i=0; i<x.Length; ++i)
{
if (y.SequenceEqual(x.Skip(i).Take(y.Length)))
{
index = i;
break;
}
}
Console.WriteLine($"{index}");
}
}
3