为什么我在这里得到IndexOutOfRangeException?

时间:2016-07-28 06:32:54

标签: c# algorithm linq

我无法弄清楚为什么我会在下面的Where条款中得到它。

using System;
using System.Linq;

public static class Extensions
{
    /// <summary>
    /// Removes consecutive characters,
    /// e.g. "aaabcc" --> "abc"
    /// </summary>
    public static void RemoveDuplicates(this string s)
    {
        var arr = s.ToCharArray()
                   .Where((i,c) => (i > 0) ? (c != s[i - 1]) : true)
                   .ToArray();
        s = new string(arr);

    }
}


public class Program
{   
    public static void Main()
    {
        var str = "aaabcc";
        str.RemoveDuplicates();
        Console.WriteLine(str);
    }
}

此外,还有一种方法可以在使用LINQ的同时使其更加高效和紧凑吗?

4 个答案:

答案 0 :(得分:5)

这里的参数顺序错误:

if(listItmes != null & listItems.size() > 0)
      cus_names = listItems.get(cus_name.getSelectedItemPosition());

应该成为:

.Where((i, c) => (i > 0) ? (c != s[i - 1]) : true)

答案 1 :(得分:2)

错误是你身边的(i,c)。

您正在使用以下可枚举扩展程序(See MSDN)

public static IEnumerable<TSource> Where<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, int, bool> predicate)

请注意,Func中的索引是 second 参数。

我认为最快的方法不是使用linq,而是字符串扩展名:

public static string RemoveDuplicates(this string s)
{
    if (String.IsNullOrEmpty(s)) return String.Empty(); // optional: return null

    var resultBuilder = new StringBuilder(s.Length);
    resultBuilder.Append(s.First());
    for (int i=1; i< s.Length; ++i)
    {
        if (s[i] != s[i-1])
            resultBuilder.Append(s[i]);
    }
    return resultBuilder.ToString();
}

但是,如果你真的想使用linq,例如因为你想附加其他linq语句,你可以模仿上面的行为,如下所示,同时仍然使用延迟加载:

public static string RemoveDuplicates(this string s)
{
    if (String.IsNullOrEmpty(s)) return String.Empty();
    s.AsEnumerable().Take(1)
        .Concat(s.AsEnumerable().Skip(1)
            .where( (c, i) => c != s[i]));
}
  • 请注意,由于检查字符串不为null,我确定有一个First()。
  • 由于Skip(1),where语句中的索引0等于s [1],而i> 0时索引i等于s [i-1]。

答案 2 :(得分:1)

您可以使用Distinct方法而不是您自己的方法来实现此目的:

var str = "aaabcca";
var result = string.Join("",str.ToCharArray().Distinct());

结果:

  

&#34; ABC&#34;

编辑:如果您想删除连续重复项,可以尝试使用此代码:

var removesequential = string.Join("",str.Where((c, i) => i == 0 || c != str[i - 1]));

结果:

  

&#34; ABCA&#34;

答案 3 :(得分:1)

您可能需要在使用Method或特殊重载之前阅读Docs

  

输入:System.Func<TSource, Int32, Boolean>

     

测试条件的每个源元素的函数; 第二   函数的参数表示源元素的索引

所以你的代码应该是这样的:

.Where((item, index) => (index > 0) ? (item != s[index - 1]) : true)