为什么我在这里得到IndexOutOfRangeException
本文关键字:IndexOutOfRangeException 在这里 为什么 | 更新日期: 2023-09-27 17:58:58
我不明白为什么在下面的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的同时,有没有一种方法可以使其更加高效和紧凑?
这里的参数顺序错误:
.Where((i, c) => (i > 0) ? (c != s[i - 1]) : true)
应该变成:
.Where((c, i) => (i > 0) ? (c != s[i - 1]) : true)
错误是where中的(i,c)。
您正在使用以下可枚举扩展(请参阅MSDN)
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, int, bool> predicate)
请注意,Func中的索引是第二个参数。
我认为最快的方法不是使用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]
在使用方法或特殊重载之前,您可能需要阅读文档:
类型:
System.Func<TSource, Int32, Boolean>
用于测试每个源元素的条件的函数;秒函数的参数表示源元素的索引
所以你的代码应该是这样的:
.Where((item, index) => (index > 0) ? (item != s[index - 1]) : true)
您可以使用Distinct
方法,而不是您自己的方法:
var str = "aaabcca";
var result = string.Join("",str.ToCharArray().Distinct());
结果:
"abc"
编辑:如果你想删除连续的重复,你可以试试这个代码:
var removesequential = string.Join("",str.Where((c, i) => i == 0 || c != str[i - 1]));
结果:
"abca"