Как создать список <T> из строки, разделенной запятой?
Учитывая переменную
string ids = Request.QueryString["ids"]; // "1,2,3,4,5";
Есть ли способ преобразовать его в список, не делая что-то вроде
List<int> myList = new List<int>();
foreach (string id in ids.Split(','))
{
if (int.TryParse(id))
{
myList.Add(Convert.ToInt32(id));
}
}
Ответы
Ответ 1
Чтобы создать список с нуля, используйте LINQ:
ids.Split(',').Select(i => int.Parse(i)).ToList();
Если у вас уже есть объект списка, опустите вызов ToList() и используйте AddRange:
myList.AddRange(ids.Split(',').Select(i => int.Parse(i)));
Если некоторые записи в строке могут не быть целыми, вы можете использовать TryParse:
int temp;
var myList = ids.Split(',')
.Select(s => new { P = int.TryParse(s, out temp), I = temp })
.Where(x => x.P)
.Select(x => x.I)
.ToList();
Один последний (более медленный) метод, который позволяет избежать Temps/TryParse, но пропускает недопустимые записи, заключается в использовании Regex:
var myList = Regex.Matches(ids, "[0-9]+").Cast<Match>().SelectMany(m => m.Groups.Cast<Group>()).Select(g => int.Parse(g.Value));
Однако это может вызвать, если одна из ваших записей переполняет int (999999999999).
Ответ 2
Это должно сделать трюк:
myList.Split(',').Select(s => Convert.ToInt32(s)).ToList();
Если список может содержать другие данные, кроме целых чисел, следует включить вызов TryParse
. См. Принятый ответ.
Ответ 3
Использование Linq:
myList.AddRange(ids.Split(',').Select(s => int.Parse(s));
Или напрямую:
var myList = ids.Split(',').Select(s => int.Parse(s));
Кроме того, чтобы предотвратить компилятор от явной генерации (в значительной степени избыточной) лямбда, рассмотрим:
var myList = ids.Split(',').Select((Func<string, int>)int.Parse);
(Подсказка: микро-оптимизация.)
Там также TryParse
, который следует использовать вместо Parse
(только), если возможен недопустимый ввод, и его следует обрабатывать молча. Однако другие разместили решения с использованием TryParse
, поэтому я, конечно, не буду. Просто имейте в виду, что вы не должны дублировать расчет.
Ответ 4
Или включая TryParse
как в вашем примере:
var res = ids.Split(',').Where(x => { int tmp; return int.TryParse(x, out tmp); }).Select(x => int.Parse(x)).ToList();
Ответ 5
Чтобы соответствовать запросу с точки зрения характеристик производительности и поведения, он должен делать то же самое и не уходить с doign regexes или не выполнять "TryParse": -
ds.Split(',')
.Select( i => {
int value;
bool valid = int.TryParse(out value);
return new {valid, value}
})
.Where(r=>r.valid)
.Select(r=>r.value)
.ToList();
Но верно, это довольно уродливо: D
Заимствование из подсказки в комментарии Джейсона: -
ds.Split(',')
.Select( i => {
int value;
bool valid = int.TryParse(out value);
return valid ? new int?( value) : null;
})
.Where(r=>r != null)
.Select(r=>r.Value)
.ToList();
или
static class Convert
{
public static Int32? ConvertNullable(this string s)
{
int value;
bool valid = int.TryParse(out value);
return valid ? new int?( value) : null;
}
}
ds.Split(',')
.Select( s => Convert.ConvertNullable(s))
.Where(r=>r != null)
.Select(r=>r.Value)
.ToList();
Ответ 6
Одна проблема заключается в том, как мы будем иметь дело со значениями, которые не являются целыми (предположим, что мы получим некоторые, которые не являются целыми). Одной из идей может быть просто использование регулярного выражения:
^ -? [0-9] + $
Теперь мы могли бы объединить все это с (как показано на примере Konrad):
var myList = ids.Split(',').Where(s => Regex.IsMatch(s, "^-?[0-9]$")).Select(s => Convert.ToInt32(s)).ToList();
Это должно выполнить эту работу.