Konwertuj ciąg [] na int [] w jednym wierszu kodu za pomocą LINQ

273

Mam tablicę liczb całkowitych w postaci ciągu:

var arr = new string[] { "1", "2", "3", "4" };

Potrzebuję szeregu „prawdziwych” liczb całkowitych, aby dalej:

void Foo(int[] arr) { .. }

Próbowałem rzucić int i oczywiście nie udało się:

Foo(arr.Cast<int>.ToArray());

Mogę teraz zrobić:

var list = new List<int>(arr.Length);
arr.ForEach(i => list.Add(Int32.Parse(i))); // maybe Convert.ToInt32() is better?
Foo(list.ToArray());

lub

var list = new List<int>(arr.Length);
arr.ForEach(i =>
{
   int j;
   if (Int32.TryParse(i, out j)) // TryParse is faster, yeah
   {
      list.Add(j);
   }
 }
 Foo(list.ToArray());

ale oba wyglądają brzydko.

Czy istnieją inne sposoby wykonania zadania?

abatishchev
źródło
3
Co jest złego w zwykłym iterowaniu jednej kolekcji, konwertowaniu wartości i dodawaniu jej do drugiej? Wydaje mi się to całkiem jasne w intencji.
Ed S.,
1
Tylko do wiadomości, używam tego pytania tutaj: stackoverflow.com/questions/1297325/…
Allen Rice
TryParse nie jest szybszy (chyba że twoje łańcuchy są nieprawidłowe, ale w takim przypadku chcesz, aby wyjątek Cię ostrzegał).
usr

Odpowiedzi:

608

Biorąc pod uwagę tablicę, możesz użyć Array.ConvertAllmetody :

int[] myInts = Array.ConvertAll(arr, s => int.Parse(s));

Dzięki Marcowi Gravellowi za wskazanie, że lambda można pominąć, co daje krótszą wersję pokazaną poniżej:

int[] myInts = Array.ConvertAll(arr, int.Parse);

Rozwiązanie LINQ jest podobne, z tym wyjątkiem, że potrzebujesz dodatkowego ToArraywywołania, aby uzyskać tablicę:

int[] myInts = arr.Select(int.Parse).ToArray();
Ahmad Mageed
źródło
4
Miły. Nie znałem tego. +1
spędza
Generowany przez to kod IL jest w rzeczywistości mniejszy niż odpowiedź Simona Foxa, FWIW
Allen Rice,
80
W rzeczywistości nie potrzebujesz lambda; ConvertAll(arr, int.Parse)wystarczy
Marc Gravell
1
Lambda jest potrzebna w VB.Net 2010: uArray = Array.ConvertAll (sNums.Split (","), Function (i) UInteger.Parse (i))
BSalita
1
@BSalita Nie, w Array.ConvertAll(arr, AddressOf Integer.Parse)
VB.Net
31

EDYCJA: aby przekonwertować na tablicę

int[] asIntegers = arr.Select(s => int.Parse(s)).ToArray();

To powinno załatwić sprawę:

var asIntegers = arr.Select(s => int.Parse(s));
Simon Fox
źródło
1
.ToArray () wymagany do spełnienia pytania OP
spędził
2
zmień var na int [] i dołącz .ToArray (), jeśli potrzebujesz go jako tablicy int
Simon Fox
19

Aby uniknąć wyjątków .Parse, oto kilka .TryParsealternatyw.

Aby użyć tylko elementów, które można przeanalizować:

string[] arr = { null, " ", " 1 ", " 002 ", "3.0" };
int i = 0; 
var a = (from s in arr where int.TryParse(s, out i) select i).ToArray();  // a = { 1, 2 }

lub

var a = arr.SelectMany(s => int.TryParse(s, out i) ? new[] { i } : new int[0]).ToArray();

Alternatywy 0dla elementów, których nie można przeanalizować:

int i; 
var a = Array.ConvertAll(arr, s => int.TryParse(s, out i) ? i : 0); //a = { 0, 0, 1, 2, 0 }

lub

var a = arr.Select((s, i) => int.TryParse(s, out i) ? i : 0).ToArray();

C # 7.0 :

var a = Array.ConvertAll(arr, s => int.TryParse(s, out var i) ? i : 0);
Slai
źródło
Drugie rozwiązanie: var a = Enumerable.Range(0, arr.Length).Where(i => int.TryParse(arr[i], out i)).ToArray();po prostu zwraca wartości 0,1,2, ... zamiast rzeczywistych wartości. Jakie jest tutaj właściwe rozwiązanie?
Beetee,
Dzięki @Beetee. Nie jestem pewien, co o tym myślałem. Zastąpiłem go inną alternatywą.
Slai,
@Slai: Dzięki. Ale co robi new int[0]? Kiedy dostaję SMS, nie dostaję do 0mojej tablicy ...
Beetee,
@Beetee new int[0]jest pustą tablicą int. Dwa pierwsze przykłady pomijają wartości, których nie można przeanalizować, a dwa ostatnie przykłady używają 0wartości, których nie można przeanalizować.
Slai,
@Slai: Ach, teraz rozumiem. Pomieszałem to z new int[] {0}. Dzięki.
Beetee,
12

możesz po prostu rzutować tablicę ciągów na tablicę int poprzez:

var converted = arr.Select(int.Parse)
A.Dara
źródło
5
miły! Dziękuję Ci. A w Dim converted = arr.Select(addressof Integer.Parse)
VB.Net
3
var asIntegers = arr.Select(s => int.Parse(s)).ToArray(); 

Musisz upewnić się, że nie otrzymasz IEnumerable<int>zwrotu

Obrabować
źródło
2
var list = arr.Select(i => Int32.Parse(i));
sepp2k
źródło