C# LINQ:转换可枚举项直到满足结束条件,如果满足结束条件则返回
我有一个可枚举的字符串C# LINQ:转换可枚举项直到满足结束条件,如果满足结束条件则返回,c#,linq,out,C#,Linq,Out,我有一个可枚举的字符串strArr。我希望尽可能将所有条目转换为int,当条目不能转换为int时,枚举应停止。我还想返回一个bool,告诉我是否可以转换所有条目 所以我要寻找的是int.TryParse的可枚举版本(如果转换成功,它将返回bool和转换后的值) 我以为可以用LINQ完成,但我想不出来。以下是我的想法: strArr. Select(s => { bool b = int.TryParse(s, out int i); return (i, b); }).
strArr
。我希望尽可能将所有条目转换为int
,当条目不能转换为int
时,枚举应停止。我还想返回一个bool
,告诉我是否可以转换所有条目
所以我要寻找的是int.TryParse
的可枚举版本(如果转换成功,它将返回bool和转换后的值)
我以为可以用LINQ完成,但我想不出来。以下是我的想法:
strArr.
Select(s => { bool b = int.TryParse(s, out int i); return (i, b); }).
// returns both the converted int value and the parsing bool for each entry
TakeWhile(ib => ib.b).
// will stop when the first parsing bool was false
Select(ib => i).ToArray();
// will only take the ints from the (int, bool) pairs and return an array
此解决方案将把转换的条目作为数组提供给我,但它不会告诉我转换是否成功。我需要一种方法来输出布尔值或可枚举值,但是如何
我知道我可以比较strArr
的长度和返回的int数组,看看转换是否成功。但我想了解LINQ的使用情况,而不仅仅是解决手头的问题(我总是可以做一些循环,根本不使用LINQ)。多亏mjwills的一点提示,我明白了:
bool parseSuccess = true;
int[] intArr = strArr.
Select(s => { parseSuccess &= int.TryParse(s, out int i); return i; }).
TakeWhile(i => parseSuccess).ToArray();
多亏了mjwills的小小暗示,我明白了:
bool parseSuccess = true;
int[] intArr = strArr.
Select(s => { parseSuccess &= int.TryParse(s, out int i); return i; }).
TakeWhile(i => parseSuccess).ToArray();
应该避免从lambda内部对变量进行变异,因为这会导致相当脆弱的代码
您可以创建自己的TakeWhilePlusOne
方法,该方法为您提供第一个未通过谓词的条目,如下所示:
static class EnumerableExt {
public static IEnumerable<TSource> TakeWhilePlusOne<TSource>(
this IEnumerable<TSource> source
, Func<TSource,bool> predicate
) {
if (source == null) throw new ArgumentNullException(nameof(source));
if (predicate == null) throw new ArgumentNullException(nameof(predicate));
return TakeWhilePlusOneIterator<TSource>(source, predicate);
}
static IEnumerable<TSource> TakeWhilePlusOneIterator<TSource>(IEnumerable<TSource> source, Func<TSource, bool> predicate) {
foreach (TSource element in source) {
var stop = !predicate(element);
yield return element;
if (stop) {
break;
}
}
}
}
您还可以使用(感谢您的评论):
应该避免从lambda内部对变量进行变异,因为这会导致相当脆弱的代码
您可以创建自己的TakeWhilePlusOne
方法,该方法为您提供第一个未通过谓词的条目,如下所示:
static class EnumerableExt {
public static IEnumerable<TSource> TakeWhilePlusOne<TSource>(
this IEnumerable<TSource> source
, Func<TSource,bool> predicate
) {
if (source == null) throw new ArgumentNullException(nameof(source));
if (predicate == null) throw new ArgumentNullException(nameof(predicate));
return TakeWhilePlusOneIterator<TSource>(source, predicate);
}
static IEnumerable<TSource> TakeWhilePlusOneIterator<TSource>(IEnumerable<TSource> source, Func<TSource, bool> predicate) {
foreach (TSource element in source) {
var stop = !predicate(element);
yield return element;
if (stop) {
break;
}
}
}
}
您还可以使用(感谢您的评论):
在LINQ设置为true
之前,有一个wassucture
bool变量。在菜单中选择dowassucture=wassucture&&b
(实际上,由于您的TakeWhile
,即使是wassucture=b;
也可以工作)。检查wassucture
的值以查看是否所有值都成功转换。我不确定这意味着什么:选择(ib=>I)
。在这个上下文中没有i
。您是否只想从ib
对象中选择整数?如果只选择整数,那么这就解释了为什么在结果数组元素上没有得到bool
属性ib
包含解析的int
和bool
。这不是你要找的吗?虽然这看起来很奇怪,因为对于每个数组元素,生成的bool
总是true
。“但它不会告诉我转换是否成功”-如果有转换结果,则这些元素的转换是成功的。我不完全清楚你在这里找什么。您的起始数据是什么?数据的成功结果是什么?您已经在第一次选择中返回了元组,为什么不在最后一次选择中执行相同的操作?@mjwills:OP已经拥有该信息,并且已经知道如何观察它。如果生成的集合小于原始集合,则并非所有元素都已转换。这看起来像是试图彻底地将简单的if
语句过度复杂化。即使在转换中设置了bool
,也需要在转换后编写if
语句来检查bool
。那么这样做可以保存什么呢?在LINQ设置为true
之前,使用wassucture
bool变量。在菜单中选择dowassucture=wassucture&&b
(实际上,由于您的TakeWhile
,即使是wassucture=b;
也可以工作)。检查wassucture
的值以查看是否所有值都成功转换。我不确定这意味着什么:选择(ib=>I)
。在这个上下文中没有i
。您是否只想从ib
对象中选择整数?如果只选择整数,那么这就解释了为什么在结果数组元素上没有得到bool
属性ib
包含解析的int
和bool
。这不是你要找的吗?虽然这看起来很奇怪,因为对于每个数组元素,生成的bool
总是true
。“但它不会告诉我转换是否成功”-如果有转换结果,则这些元素的转换是成功的。我不完全清楚你在这里找什么。您的起始数据是什么?数据的成功结果是什么?您已经在第一次选择中返回了元组,为什么不在最后一次选择中执行相同的操作?@mjwills:OP已经拥有该信息,并且已经知道如何观察它。如果生成的集合小于原始集合,则并非所有元素都已转换。这看起来像是试图彻底地将简单的if
语句过度复杂化。即使在转换中设置了bool
,也需要在转换后编写if
语句来检查bool
。那么这样做会保存什么呢?如果strArr
为空,则返回true
——这就是您想要的吗?可能吧,我只是澄清一下。是的,这是正确的。在空字符串数组中,没有任何东西会导致转换失败,因此没有理由返回false
。虽然这会起作用,但我个人不喜欢在linq语句中对局部变量产生副作用。linq是函数式编程,它有点违反它,因为它有副作用。我没有真正看到它的好处。在此转换之后,您仍然需要检查结果。您试图避免编写if
语句来比较