我有这个功能:
public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable)
{
return iterable.Distinct();
}
这适用于任何IEnumerable,除了字符串,我必须使用此调用进行测试:
Assert.AreEqual("ABCDAB", UniqueInOrder("AAAABBBCCDAABBB"));
断言失败:
Expected is <System.String>, actual is <System.Linq.Enumerable+<DistinctIterator>c__Iterator10`1[System.Char]>
Values differ at index [4]
我也尝试过这样的事情:
public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable)
{
return "abc";
}
但我有编译错误:
Cannot implicitly convert type 'string' to 'System.Collections.Generic.IEnumerable<T>'
怎么可能用字符串调用函数但是我不能返回字符串?类型仍然是IEnumerable&lt; T&gt;
有什么想法吗? 谢谢!
EDITED: Distinct()错了,我改为:
public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable)
{
List<T> result = new List<T>();
foreach (var c in iterable.ToList())
if (result.LastOrDefault() == null || !result.LastOrDefault().Equals(c))
result.Add(c);
return result;
}
现在所有的测试都在通过!谢谢!
答案 0 :(得分:7)
实际上字符串是一组字符,因此当您使用UniqueInOrder("AAAABBBCCDAABBB")
时,您会调用UniqueInOrder<char>
来代替UniqueInOrder<string>
。因此,该方法的返回值也将是IEnumerble<char>
,而不仅仅是字符串。
因此,您应该将返回值方法与一组字符进行比较,例如:
CollectionAssert.AreEqual(new[] { 'A', 'B', 'C', 'D', 'A' 'B', 'Ä' }, UniqueInOrder(...));
或更容易:
CollectionAssert.AreEqual(expected.ToCharArray(), UniqueInOrder(...));
但即便如此,您的测试也会失败,因为Distinct
将过滤掉所有重复项。
如果要检查两个序列是否完全相同,可以改为使用SequenceEqual
:
var equal = firstColl.SequenceEqual(second);
编辑:显然你试图删除所有序列中的双重字符。你可以用这个:
public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable) where T : IEquatable<T>
{
T previous = default(T);
foreach (var t in iterable)
{
if (!t.Equals(previous))
yield return t;
previous = t;
}
}
现在您可以调用它并将其与预期输出进行比较,例如:
var actual = new String(UniqueInOrder("AABBCCDDAABB").ToArray());
var expected "ABCDAB";
Assert.AreEqual(expected, actual);
答案 1 :(得分:2)
Himbrombeere解释了为什么断言因类型问题而失败。但它也会失败,因为Distinct
不符合你的期望。它将删除所有重复的字母,而不仅仅是连续的字母。因此它将返回ABCD
而不是ABCDAB
。
这将做你想要的,断言将通过:
public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable, EqualityComparer<T> comparer = null)
{
if (comparer == null) comparer = EqualityComparer<T>.Default;
bool first = true;
T lastItem = default(T);
foreach(T thisItem in iterable)
{
if (first || !comparer.Equals(thisItem, lastItem))
{
first = false;
yield return thisItem;
}
lastItem = thisItem;
}
}
Assert.AreEqual("ABCDAB", String.Conat(UniqueInOrder("AAAABBBCCDAABBB")));
答案 2 :(得分:1)
关于问题的第一部分,断言失败的原因是.Distinct()
致电
UniqueInOrder("AAAABBBCCDAABBB");
此方法:
private IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable)
{
return iterable.Distinct();
}
将返回{'A', 'B', 'C', 'D'}
然而这种方法:
private IEnumerable<T> RemovesDupesInOrder<T>(IEnumerable<T> iterable)
{
List<T> result = new List<T>();
T last = default(T);
iterable.ToList().ForEach(t =>
{
if (t.Equals(last) == false)
{
last = t;
result.Add(t);
}
});
return result;
}
会返回{'A', 'B', 'C', 'D', 'A', 'B'}
请注意:t.Equals(last)
可能会或可能不会按照您的参考类型执行。
答案 3 :(得分:0)
UniqueInOrder("AAAABBBCCDAABBB")
返回"ABCD"
,因为它们是字符串中的不同字符。这不等于"ABCDAB"
,差异在于第5个字符(或代码字中的字符4,因为am IEnumerable
是0索引的。)
这正是断言失败告诉你的。枚举中的元素与索引4的字符不同。具体来说,在索引不存在的第二个参数中。 Assert.AreEqual("ABCD", UniqueInOrder("AAAABBBCCDAABBB"))
可以正常使用
return "abc"
案例中出现编译错误,因为"abc"
(字符串)不是通用IEnumerable
。如果传入IEnumerable<int>
,则类型将不兼容,因此必须是编译器错误