2009-11-19 2 views
40

Я нашел способ сделать это наоборот: создать строку с разделителями-запятыми из списка или массива int, но не о том, как преобразовать ввод, например string str = "1,2,3,4,5";, в массив или список целых чисел.Преобразовать разделенную запятыми строку ints в массив int

Вот моя реализация (вдохновленный this post by Eric Lippert):

public static IEnumerable<int> StringToIntList(string str) 
    { 
     if (String.IsNullOrEmpty(str)) 
     { 
      yield break; 
     } 

     var chunks = str.Split(',').AsEnumerable(); 

     using (var rator = chunks.GetEnumerator()) 
     { 
      while (rator.MoveNext()) 
      { 
       int i = 0; 

       if (Int32.TryParse(rator.Current, out i)) 
       { 
        yield return i; 
       } 
       else 
       { 
        continue; 
       } 
      } 
     } 
    } 

Как вы думаете, это хороший подход или есть более простой, может быть, даже встроенный в пути?

EDIT: Извините за путаницу, но метод должен обрабатывать недопустимый ввод как "1,2,,,3" или "###, 5," и т.д., пропуская его.

+0

Вы напрасно усложнять код, не используя 'foreach'. Сообщение, которое вы копируете, решает _completely_ другую проблему. – SLaks

ответ

50

Вы должны использовать цикл Еогеаспа, например:

public static IEnumerable<int> StringToIntList(string str) { 
    if (String.IsNullOrEmpty(str)) 
     yield break; 

    foreach(var s in str.Split(',')) { 
     int num; 
     if (int.TryParse(s, out num)) 
      yield return num; 
    } 
} 

Обратите внимание, что как ваш оригинальный пост, это будет игнорировать цифры, которые не могут быть разобраны.

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

return (str ?? "").Split(',').Select<string, int>(int.Parse); 
+1

Спасибо, хороший! Еще проще, чем мой подход. Тем не менее, существует {отсутствует после foreach. – Max

+0

Исправлено; Благодарю. – SLaks

2

Это для долгого времени, но вы можете легко его модифицировать для работы с ints.

private static long[] ConvertStringArrayToLongArray(string str) 
{ 
    return str.Split(",".ToCharArray()).Select(x => long.Parse(x.ToString())).ToArray(); 
} 
+0

Это набросит на неповторимые числа; он, кажется, хочет пропустить их. – SLaks

+0

Это не то же самое. Его версия грамотно обрабатывает нецелые числа, пропуская их. – mquander

+0

Хорошая точка, но я шел по входному примеру, который он предоставил: string str = "1,2,3,4,5" – dcp

1

Я не понимаю, почему вынимая переписчик явно предлагает Вам любое преимущество перед использованием foreach. Также нет необходимости звонить AsEnumerable по телефону chunks.

0

Я думаю, что это достаточно. Понятно, что он ленив, поэтому он будет быстрым (за исключением, возможно, первого случая, когда вы разделите строку).

+0

Я не согласен; это _really_ должно использовать 'foreach', что сделает его намного яснее. Кроме того, это бесполезно многословие. – SLaks

+0

Я сказал, достаточно хорошо, не идеально. Это не повредит моим глазам, вы просто пускаете это так, как есть, и отправляйтесь на другое ... –

52

Если вы не хотите, чтобы текущее поведение обработки ошибок, это очень просто:

return text.Split(',').Select(x => int.Parse(x)); 

В противном случае, я бы использовать дополнительный вспомогательный метод (as seen this morning!):

public static int? TryParseInt32(string text) 
{ 
    int value; 
    return int.TryParse(text, out value) ? value : (int?) null; 
} 

и:

return text.Split(',').Select<string, int?>(TryParseInt32) 
         .Where(x => x.HasValue) 
         .Select(x => x.Value); 

или если вы не хотите использовать преобразование метод группы:

return text.Split(',').Select(t => t.TryParseInt32(t) 
         .Where(x => x.HasValue) 
         .Select(x => x.Value); 

или в форме выражения запроса:

return from t in text.Split(',') 
     select TryParseInt32(t) into x 
     where x.HasValue 
     select x.Value; 
+0

Для парня java/C# ваши ответы всегда кажутся мне очень функциональными: =) – Peter

+0

Когда дело доходит до LINQ, это не совсем удивительно :) –

+0

Почему вы не хотите использовать преобразование группы методов? – SLaks

4

Это было предложено ранее. .Net имеет встроенную функцию ConvertAll для преобразования между массивом одного типа в массив другого типа.Вы можете совместить это с Сплите, чтобы отделить строку в массив строк

Пример функции:

static int[] ToIntArray(this string value, char separator) 
{ 
    return Array.ConvertAll(value.Split(separator), s=>int.Parse(s)); 
} 

Taken from here

6

--EDIT-- Похоже, я взял свой вопрос заголовок слишком буквально - он просил массив целых чисел, а не список --edit ENDS--

еще один вспомогательный метод ...

private static int[] StringToIntArray(string myNumbers) 
{ 
    List<int> myIntegers = new List<int>(); 
    Array.ForEach(myNumbers.Split(",".ToCharArray()), s => 
    { 
     int currentInt; 
     if (Int32.TryParse(s, out currentInt)) 
      myIntegers.Add(currentInt); 
    }); 
    return myIntegers.ToArray(); 
} 

быстрый тест-код для него, тоже ...

static void Main(string[] args) 
{ 
    string myNumbers = "1,2,3,4,5"; 
    int[] myArray = StringToIntArray(myNumbers); 
    Console.WriteLine(myArray.Sum().ToString()); // sum is 15. 

    myNumbers = "1,2,3,4,5,6,bad"; 
    myArray = StringToIntArray(myNumbers); 
    Console.WriteLine(myArray.Sum().ToString()); // sum is 21 

    Console.ReadLine(); 
} 
22

без использования функции лямбды и для действительных входов только, я думаю, что это понятнее сделать это:

Array.ConvertAll<string, int>(value.Split(','), Convert.ToInt32); 
+1

Я нашел Мне не нужна эта часть '' –

0

Я люблю простой решение, которое сработало для меня.

String.Join(",",str.Split(','));