Вставить разделенную строку в список <int> - PullRequest
6 голосов
/ 29 июня 2010

Если у меня есть, например, следующая строка:

"123; 3344; 4334; 12"

, и я хочу, чтобы эти числа были в общем виде List<int>, я думаю, что я неЗдесь не существует хорошего способа, кроме как разбить цикл и выполнить преобразование, а затем добавить к List<int> через каждую итерацию.У кого-нибудь есть другие способы сделать это?

Обновлено.Вот что я придумал.Я хочу сделать это по-старому, а не с LINQ, потому что я пытаюсь стать лучше, используя только строки, массивы, списки, манипулируя и конвертируя в целом.

public List<int> StringToList(string stringToSplit, char splitDelimiter)
{
    List<int> list = new List<int>();

    if (string.IsNullOrEmpty(stringToSplit))
        return list;

    string[] values = stringToSplit.Split(splitDelimiter);

    if (values.Length <= 1)
        return list;

    foreach (string s in values)
    {
        int i;
        if (Int32.TryParse(s, out i))
            list.Add(i);
    }

    return list;
}

Это новая утилита для работы со строкамиметод, который я планирую использовать всякий раз, когда мне нужно преобразовать список строк с разделителями в список

, поэтому я возвращаю пустой список обратно вызывающей стороне, если что-то не получается.Хорошо плохо?это довольно распространенное явление?

Да, есть более «изящные» способы сделать это с помощью LINQ, но я хочу сделать это вручную… старый способ на данный момент только для моего собственного понимания.

Кроме того, что меня беспокоит:

list.AddRange(str.Split(';').Select(Int32.Parse));

, так это то, что я понятия не имею:

  1. Как запихнуть в TryParse вместо этого.
  2. Что, если str.Split(';').Select(Int32.Parse) просто не получится по какой-то причине ... тогда метод, в котором находится этот AddRange, взорвется, и если я не добавлю попытку / ловушку вокруг всего этого, я облажалсяесли я не справлюсь должным образом.

Ответы [ 5 ]

6 голосов
/ 29 июня 2010
static int? ToInt32OrNull(string s)
{
    int value;
    return (Int32.TryParse(s, out value)) ? value : default(int?);      
}
// ...
var str = "123;3344;4334;12"; 
var list = new List<int>();
list.AddRange(str.Split(';')
                 .Select(ToInt32OrNull)
                 .Where(i => i != null)
                 .Cast<int>());

Примечания спрашивающего:

Я не знаю другого хорошего способа, кроме как разбить цикл и выполнить преобразование, а затем добавить в список

В общем, это основная причина, по которой LINQ был перенесен в C # - чтобы избавить от необходимости работать с последовательностями значений путем реализации циклов, а вместо этого просто объявить о своем намерении преобразовать последовательность.Если вы когда-нибудь подумаете: «Я не знаю, как это сделать, кроме как с помощью цикла», - пришло время изучить конструкцию LINQ, которая сделает эту работу за вас.

Обновление производительности:

Производительность LINQ была задана ниже.Хотя в комментариях отстаивается идея о том, что LINQ медленнее, так как мы получаем преимущества читабельности, удобства сопровождения и компоновки, есть еще один аспект, который дает LINQ простое преимущество в производительности: параллелизм.Вот пример, где при добавлении только одного вызова метода расширения AsParallel() удваивает производительность.Это отличный пример того, где масштабирование превосходит микрооптимизацию, даже не требуя очень тщательных измерений.Заметьте, я не утверждаю, что микрооптимизации никогда не нужны, но с инструментами, которые мы имеем в наличии на этом уровне абстракции, потребность становится исчезающе малой.

class Program
{
    private const int ElementCount = 10000000;

    static void Main(string[] args)
    {
        var str = generateString();
        var stopwatch = new Stopwatch();

        var list1 = new List<int>(ElementCount); 
        var list2 = new List<int>(ElementCount);

        var split = str.Split(';');

        stopwatch.Start();
        list1.AddRange(split
                          .Select(ToInt32OrNull) 
                          .Where(i => i != null) 
                          .Cast<int>());
        stopwatch.Stop();

        TimeSpan nonParallel = stopwatch.Elapsed;

        stopwatch.Restart();

        list2.AddRange(split
                          .AsParallel()
                          .Select(ToInt32OrNull)
                          .Where(i => i != null)
                          .Cast<int>());

        stopwatch.Stop();

        TimeSpan parallel = stopwatch.Elapsed;

        Debug.WriteLine("Non-parallel: {0}", nonParallel);
        Debug.WriteLine("Parallel: {0}", parallel);
    }

    private static String generateString()
    {
        var builder = new StringBuilder(1048576);
        var rnd = new Random();

        for (int i = 0; i < ElementCount; i++)
        {
            builder.Append(rnd.Next(99999));
            builder.Append(';');
        }

        builder.Length--;

        return builder.ToString();
    }

    static int? ToInt32OrNull(string s)
    {
        int value;
        return (Int32.TryParse(s, out value)) ? value : default(int?);
    } 
}

Непараллельно:00: 00: 07.0719911

Параллельно: 00: 00: 04.5933906

5 голосов
/ 29 июня 2010
string str = "123;3344;4334;12";
List<int> list = new List<int>();

foreach (string s in str.Split(';'))
{
    list.Add( Int32.Parse(s));
}
3 голосов
/ 29 июня 2010
List<int> list = (from numString in "123;3344;4334;12".Split(';') 
                  select int.Parse(numString)).ToList();
1 голос
/ 29 июня 2010
string myString = "123;3344;4334;12";
var ints = new List<int>();
(from s in myString.Split(';')
 select int.Parse()).ToList().ForEach(i=>ints.Add(i));

Я слышал, что .Net 4.0, возможно, добавил ForEach к Enumerable<T>, поэтому ToList там может быть ненужным (не могу проверить).

0 голосов
/ 22 июля 2013

Я думаю, что это самое простое

  var str = "123;3344;4334;12"; 
  var list = str.Split(';').ToList().Cast<int>();
...