Как игнорировать в Linq значения, которые не конвертируются в double?

kovdryavlad

d = System.IO.File.ReadAllLines(filename)
                .SelectMany(str => str.Split(new[] { ' ', '\t' },StringSplitOptions.******************))
                .Select(str => Convert.********(str.Replace('.', ',')))
                .ToArray();
3 ответа

kovdryavlad

Обновление

Если вам нужно проверять числа из нескольких языков, проще делать это явно:

static CultureInfo englishCI = CultureInfo.GetCultureInfo("en-US");
static CultureInfo russianCI = CultureInfo.GetCultureInfo("ru-RU");
.Select(s => ******.TryParse(
                 s, NumberStyles.Float, englishCI,
                 out var de) ? de :
             ******.TryParse(
                 s, NumberStyles.Float, russianCI,
                 out var dr) ? dr :
             (******?)null)
.OfType<******>()
.ToArray();
</******>

Обновление

Нашёл более изящный вариант:

.Select(s => ******.TryParse(
                 s, NumberStyles.Float, CultureInfo.InvariantCulture,
                 out var d) ? d : (******?)null)
.OfType<******>()
.ToArray();
</******>

По идее, вам нужно что-то такое:

.Select(s => ******.TryParse(
                 s, NumberStyles.Float, CultureInfo.InvariantCulture,
                 out var d) ? d : (******?)null)
.Where(v => v.HasValue)
.Select(v => v.Value)
.ToArray();

Пояснение:

  1. Вам не нужно заменять точку на запятую для разбора чисел, вы должны вместо этого использовать правильную локаль. Иначе в незнакомой локали ваш код не будет работать.
  2. В новой версии языка вы можете объявлять переменную прямо внутри out-клаузы.
  3. В качестве маркерного значения лучше использовать то, которое не может встретиться в типе ******. Я взял null, для этого пришлось расширить тип до ******?. Возможно, можно было бы обойтись просто использованием ******.NaN.
  4. После фильтрации нужно «вернуться» от ******? назад к ******.

Для Visual Studio 2015 у вас не выйдет использовать out var, и придётся писать более длинно:

.Select(s =>
{
    ****** d;
    return ******.TryParse(
               s, NumberStyles.Float, CultureInfo.InvariantCulture,
               out d) ? d : (******?)null;
})
.Where(v => v.HasValue)
.Select(v => v.Value)
.ToArray();


kovdryavlad

Linq не серебряная пуля, не стоит все делать через него, так почему бы не написать свой метод расширения? Может не самый лаконичный способ, но вполне рабочий и нет передачи nullов с последующей проверкой

public class Program
{
    public static void Main()
    {
        var l = new List<string>{"1.7", "1.3s", "1.3", "1.13"};
        l.**********().ToList().ForEach(t=>Console.WriteLine(t));
    }
}

static class Ex
{
    public static IEnumerable<******> **********(this IEnumerable<string> arg)
    {
        foreach (var str in arg)
            if (******.TryParse(str, out var d))
                yield return d;
    }
}
</string></******></string>


kovdryavlad

Если файл не предполагает наличие нулевых значений (default(******)), то можете воспользоваться методом ******.TryParse():

d = System.IO.File.ReadAllLines(filename)
                .SelectMany(str => str.Split(new[] { ' ', '\t' }, StringSplitOptions.******************))
                .Select(str => {
                    ****** value;
                    var isParsed = ******.TryParse(str.Replace('.', ','), out value);

                    if (isParsed)
                        return value;
                    else
                        return default(******);
                })
                .Where(d => d != default(******))
                .ToArray();

licensed under cc by-sa 3.0 with attribution.