使用LINQ(清洁方式)转换List <int>中的字符串

时间:2017-06-20 23:05:48

标签: c# linq out tryparse

我有这个字符串:

string input = "1,2,3,4,s,6";

注意s字符。

我只想使用LINQ在List<int>中转换此字符串。我最初以这种方式尝试过:

var myList = new List<int>();
input.Split(',').ToList().ForEach(n =>
    myList.Add(int.TryParse(n, out int num) ? num : -1)
);
lista.RemoveAll(e => e == -1);

但我更喜欢没有-1而不是无数字符。

所以现在我尝试这个:

var myList = new List<int>();
input.Split(',').ToList()
    .FindAll(n => int.TryParse(n, out int _))
    .ForEach(num => myList.Add(int.Parse(num)));

我更喜欢这个,但是解析发生两次(首先是TryParse然后是Parse)真的很遗憾。但是,根据我的理解,TryParse中的out变量是无用的(或不是?)。

你有其他人建议(使用LINQ)吗?

9 个答案:

答案 0 :(得分:2)

public class ParsesStringsToIntsWithLinq
{
    public IEnumerable<int> Parse(string input)
    {
        var i = 0;
        return (from segment in input.Split(',')
            where int.TryParse(segment, out i) 
            select i);
    }
}

[TestClass]
public class Tests
{
    [TestMethod]
    public void IgnoresNonIntegers()
    {
        var input = "1,2,3,4,s,6";
        var output = new ParsesStringsToIntsWithLinq().Parse(input);
        Assert.IsTrue(output.SequenceEqual(new []{1,2,3,4,6}));
    }
}

它不会返回List<int>,但我必须在某处画线。你可以列出一个清单。

答案 1 :(得分:1)

使用一个很好的扩展方法

public static IEnumerable<T> AsSingleton<T>(this T source) {
    yield return source;
}

(如果愿意,可以用new[] { n }替换)

input.Split(',').SelectMany(s => Int32.TryParse(s, out var n) ? n.AsSingleton()  : Enumerable.Empty<int>()).ToList()

答案 2 :(得分:0)

你可以这样做:

List<int> numbers = input
    .Split(',')
    .Where(t => int.TryParse(t, out int a))
    .Select(int.Parse)
    .ToList();

答案 3 :(得分:0)

我更喜欢做一个好帮手功能:

Func<string, int?> tryParse = s => int.TryParse(s, out int n) ? (int?)n : null;

然后解决这个问题很简单:

string input = "1,2,3,4,s,6";

List<int> myList =
    input
        .Split(',')
        .Select(s => tryParse(s))
        .Where(n => n.HasValue)
        .Select(n => n.Value)
        .ToList();

这给出了:

1 
2 
3 
4 
6 

答案 4 :(得分:0)

int i = 0; 
var myList = (from s in input.Split(',') where int.TryParse(s, out i) select i).ToList();

如果数字始终是单个ASCII数字:

var myList = "1,2,3,4,s,6".Select(c => c ^ 48).Where(i => i < 10).ToList();

RegEx替代方案很少有趣:

var myList2 = Regex.Split("1,2,3,4,s,6", "[^0-9]+").Select(int.Parse).ToList(); // if the string starts and ends with digits

var myList3 = Regex.Replace("1,2,3,4,s,6", "[^0-9]+", " ").Trim().Split(' ').Select(int.Parse).ToList();

var myList4 = Regex.Matches("1,2,3,4,s,6", "[0-9]+").Cast<Match>().Select(m => int.Parse(m.Value)).ToList();

答案 5 :(得分:0)

为什么必须是LINQ?

尝试:

//Come up a better name...
public static List<int> ConvertToIntListNoLinq(string input)
{
    List<int> output = new List<int>();
    foreach(string s in input.Split(','))
    {
        if(int.TryParse(s, out int result))
        {
            output.Add(result);
        }               
    }
    return output;
}

Fiddle

答案 6 :(得分:0)

这是一个通用的LINQ扩展,它使用cap_ios.h。这将允许您传入一个返回delegate的函数,同时“保留”bool变量的结果(如out)。

用法:

int.TryParse

代码:

string input = "1,2,3,4,s,6";
List<int> myList = input.Split(',').SelectTry<string, int>(int.TryParse).ToList();

答案 7 :(得分:0)

我认为这也是一种干净的方法。即使它使用了额外的变量,我们获得的好处是它干净且易于理解。

string ids = "2,4,2,4,5,s"
const int inValidInt = -99;
var ids = ids.Split(',')
.Select(id =>
{
    int parsedId = int.TryParse(id, out parsedId) ? parsedId : inValidInt;
    return parsedId;
})
.Where(x => x != inValidInt).ToList();

答案 8 :(得分:-1)

  • 您无需致电.Split(...).ToList(),因为String[]已经可以枚举。
  • 您可以在带有大括号的lambda中使用多个语句。
  • FindAllForEachRemoveAll方法不是Linq方法,它们是List<T>的成员。他们的Linq等价物为Where

像这样:

List<Int32> numbers = "1,2,3,4,s,6"
    .Split(',')
    .Select( s => { Int32 val; return Int32.TryParse( s, NumberStyles.Integer, CultureInfo.InvariantCulture, out val ) ? val : -1 } )
    .Where( n => n != -1 )
    .ToList();

您可以使用辅助方法使其更简洁:

static Int32 Parse(String s) {
    Int32 ret;
    if( Int32.TryParse( s, NumberStyles.Integer, CultureInfo.InvariantCulture, out ret ) ) {
        return ret;
    }
    return -1;
}

变为:

List<Int32> numbers = "1,2,3,4,s,6"
    .Split(',')
    .Select( s => Parse( s ) )
    .Where( n => n != -1 )
    .ToList();

如果您不想保留-1,则可以使用可为空的整数:

static Int32? Parse(String s) {
    Int32 ret;
    if( Int32.TryParse( s, NumberStyles.Integer, CultureInfo.InvariantCulture, out ret ) ) {
        return ret;
    }
    return null;
}

List<Int32> numbers = "1,2,3,4,s,6"
    .Split(',')                     // String to String[]
    .Select( s => Parse( s ) )      // String[] to IEnumerable<Int32?>
    .Where( n => n != null )        // filter out nulls
    .Select( n => n.Value )         // IEnumerable<Int32?> to IEnumerable<Int32>
    .ToList();                      // IEnumerable<Int32> to List<Int32>