我正在尝试编写这样的扩展方法:
git branch -f
但是,编译器告诉我git rebase
没有User
User ID
Video
VideoID
LikedBy (Subcol)
User ID
User ID
User ID
方法。只有static class MyExtensions
{
public static int FindSubArray(this Array x, Array y)
{
int offset = 0;
for (int i = 0; i < x.Length; ++i)
{
if (y.SequenceEqual(x.Skip(i).Take(y.Length)))
{
offset = i;
break;
}
}
return offset;
}
}
可以做到:
错误CS1061:“数组”不包含“跳过”的定义,并且没有可访问的扩展方法“跳过”
但是当我将参数类型更改为Array
时,它说.Skip()
没有IEnumerable
属性,只有IEnumerable<T>
有。
错误CS1061:“ IEnumerable”不包含“ Length”的定义,并且没有可访问的扩展方法“ Length”
当我在扩展方法之外编写类似的代码时,两种类型都为IEnumerable
,使用.Length
和Array
并没有问题,因为它很容易转换byte[]
到.Skip()
的位置。
如何编写扩展方法以同时使用.Length
和byte[]
?
答案 0 :(得分:3)
您可以使方法通用并更改参数类型:
public static int FindSubArray<T>(this T[] x, T[] y) { ... }
或者,您可以使用实现IReadOnlyCollection<T>
并具有IEnumerable<T>
属性的Count
:
public static int FindSubArray<T>(this IReadOnlyCollection<T> x, IReadOnlyCollection<T> y)
{
int offset = 0;
for (int i = 0; i < x.Count; ++i)
{
if (y.SequenceEqual(x.Skip(i).Take(y.Count)))
{
offset = i;
break;
}
}
return offset;
}
值得注意的是,这种寻找子序列的方法不是很有效,您可能想看看其他算法,例如Boyer-Moore或Knuth-Morris-Pratt。
答案 1 :(得分:1)
更改签名并使用它
public static int FindSubArray<T>(this IReadOnlyList<T> sourceCollection, IReadOnlyList<T> collectionToFind)
{
for (var i = 0; i <= sourceCollection.Count - collectionToFind.Count; i++)
{
var matched = true;
for (var j = 0; j < collectionToFind.Count; j++)
{
if (sourceCollection[i + j].Equals(collectionToFind[j]))
continue;
matched = false;
break;
}
if (matched)
return i;
}
return -1;
}
答案 2 :(得分:0)
如果您真的想使用Array
,可以。对于大多数值类型而言,它的性能不如泛型,因为它们将装在object
内,并且必须完成泛型Equals
方法测试,但有可能。无需使用LINQ,只需实现自己的序列比较即可。另外,不要太远,以至于尝试匹配子序列时会跑到最后。
最后,由于找不到-1
,所以返回0
。
static class MyExtensions {
public static int FindSubArray(this Array x, Array y) {
for (int i = 0; i < x.Length-y.Length+1; ++i) {
var found = true;
for (int j = 0; j < y.Length; ++j) {
if (!((IList)x)[i + j].Equals(((IList)y)[j])) {
found = false;
break;
}
}
if (found)
return i;
}
return -1;
}
}
答案 3 :(得分:0)
您可以将IEnumerable与Count一起使用,而不要使用Length属性。
public static class MyExtensions
{
public static int FindSubArray<T>(this IEnumerable<T> x, IEnumerable<T> y)
{
int offset = 0;
for (int i = 0; i < x.Count(); ++i)
{
if (y.SequenceEqual(x.Skip(i).Take(y.Count())))
{
offset = i;
break;
}
}
return offset;
}
答案 4 :(得分:0)
这是一个允许您使用Array
和 SequenceEquals()
的解决方案。 (尽管我会回覆其他人,他们认为这不是一个非常有效的解决方案,也不可能是最方便的解决方案。)
public static int FindSubArray(this Array x, Array y)
{
int offset = 0;
var loYArray = new List<Object>();
var ieYArray = y.GetEnumerator();
while (ieYArray.MoveNext())
loYArray.Add(ieYArray.Current);
for (int i = 0; i < x.Length; ++i)
{
var loXSubArray = new List<Object>();
var ieXArray = x.GetEnumerator();
var iSkip = 0;
while (ieXArray.MoveNext())
{
iSkip++;
if (iSkip > i)
loXSubArray.Add(ieXArray.Current);
if (loXSubArray.Count >= y.Length)
break;
}
if (loYArray.SequenceEqual(loXSubArray))
return i;
}
return -1;
}
此解决方案使用“对象”装箱并创建阵列的多个冗余副本。如果您不需要使用Array
或SequenceEquals()
,我建议使用@NetMage的解决方案。