c#将字符串转换为IEnumerable <t>

时间:2017-10-27 14:11:53

标签: c# string generics casting ienumerable

我有这个功能:

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;
}

现在所有的测试都在通过!谢谢!

4 个答案:

答案 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>,则类型将不兼容,因此必须是编译器错误