我有一个可枚举的字符串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
此解决方案会将转换后的条目作为数组提供给我,但它不会告诉我转换是否成功。我需要一种方法out
bool或enumerable,但是怎么样?
我知道我可以比较strArr
和返回的int数组的长度,看看转换是否成功。但是我想了解LINQ的用法,而不仅仅是解决手头的问题(我总是可以做一些循环,从不使用LINQ)。
答案 0 :(得分:2)
感谢mjwills'我得到了一点暗示:
bool parseSuccess = true;
int[] intArr = strArr.
Select(s => { parseSuccess &= int.TryParse(s, out int i); return i; }).
TakeWhile(i => parseSuccess).ToArray();
答案 1 :(得分:1)
应该避免从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;
}
}
}
}
注意:此实现是TakeWhile
in the reference source的修改。
现在您可以使用此方法实现以下目标:
var pairs = strArr
.Select(s => new { ParseSuccess = int.TryParse(s, out int i), Value = i })
.TakeWhilePlusOne(i => i.ParseSuccess)
.ToArray();
var intArray = pairs.Where(p => p.ParseSuccess).Select(p => p.Value).ToArray();
var allValuesAreGood = pairs.LastOrDefault()?.ParseSuccess ?? true;
您还可以使用TakeUntil
from morelinq library(感谢mjwills评论):
var pairs = strArr
.Select(s => new { ParseSuccess = int.TryParse(s, out int i), Value = i })
.TakeUntil(i => !i.ParseSuccess)
.ToArray();
var intArray = pairs.Where(p => p.ParseSuccess).Select(p => p.Value).ToArray();
var allValuesAreGood = pairs.LastOrDefault()?.ParseSuccess ?? true;