konwertuj listę obiektów z jednego typu na inny za pomocą wyrażenia lambda

224

Mam pętlę foreach, która czyta listę obiektów jednego typu i tworzy listę obiektów innego typu. Powiedziano mi, że wyrażenie lambda może osiągnąć ten sam wynik.

var origList = List<OrigType>(); // assume populated
var targetList = List<TargetType>(); 

foreach(OrigType a in origList) {
    targetList.Add(new TargetType() {SomeValue = a.SomeValue});
}

Jakakolwiek pomoc byłaby mile widziana - jestem nowy dzięki lambda i linq dzięki, s

Stratton
źródło
@mmcrae to pytanie jest nowsze niż to
Andy Wiesendanger,

Odpowiedzi:

312

Spróbuj wykonać następujące czynności

var targetList = origList
  .Select(x => new TargetType() { SomeValue = x.SomeValue })
  .ToList();

Wykorzystuje kombinację Lambdas i LINQ, aby osiągnąć rozwiązanie. Funkcja Wybierz jest metodą stylu projekcji, która zastosuje przekazane w delegacie (lub w tym przypadku lambda) do każdej wartości w oryginalnej kolekcji. Wynik zostanie zwrócony w nowym IEnumerable<TargetType>. Wywołanie .ToList to metoda rozszerzenia, która przekształci to IEnumerable<TargetType>w List<TargetType>.

JaredPar
źródło
Czy można to zrobić bez konkretnego wdrożenia TargetType? Skończyło się na czymś takim: List<ISearchEntity> results = myIQueryable.Select(x => (ISearchEntity) new TargetType { MyField = "Field value is " + x.TargetField }).ToList();gdzie celem było zdobycie obiektu typuList<ISearchEntity>
Aaron Newton
220

Jeśli wiesz, chcesz przekonwertować z List<T1>do List<T2>wtedy List<T>.ConvertAllbędzie nieco bardziej wydajny niż Select/ ToListponieważ zna dokładny rozmiar na początek:

target = orig.ConvertAll(x => new TargetType { SomeValue = x.SomeValue });

W bardziej ogólnym przypadku, gdy znasz tylko źródło jako IEnumerable<T>, możesz użyć Select/ ToList. Państwo mogli również twierdzą, że w świecie, z LINQ, to bardziej idiomatyczne zacząć ... ale warto przynajmniej zdając sobie sprawę z ConvertAllmożliwości.

Jon Skeet
źródło
1
na początku nie sądziłem, że mógłbym to zrobić, ponieważ miałem do czynienia z niepoliczalną liczbą (dla listy źródeł i nie zapewnia ona opcji konwersji), więc zadzwoniłem na nią .ToList (), a teraz próbuję przekonwertować - lubię to lepiej niż wstawianie niefiltrującego „gdzie”
Stratton,
2
Dlaczego miałbyś potrzebować gdzie? Jeśli masz tylko, po IEnumerable<T>prostu zadzwoń Selecti ToListzgodnie z odpowiedzią Jareda.
Jon Skeet,
Dla innych początkujących, takich jak ja, możesz również wywołać metodę podobną dox => buildTargetType(x)
Snekse
55
var target = origList.ConvertAll(x => (TargetType)x);
Turnia
źródło
1
Jaka jest ta składnia? To nie przypomina lambda. Doceniamy link do dokumentacji. Dzięki, ale tutaj działa dobrze
Pierre de LESPINAY
Argumentem ConvertAll jest zwykła lambda C #, prawda?
avl_sweden
1
wygląda ładnie, ale potrzebuje pewnego kontekstu, kiedy (lub jeśli) można go użyć. Właśnie tego spróbowałem i otrzymywałem cannot cast expressionwyjątek
Collin M. Barrett
31
List<target> targetList = new List<target>(originalList.Cast<target>());
Pranaw
źródło
5
-1 działałoby to tylko wtedy, gdyby rzutowanie było możliwe, aw przypadku PO wydaje się, że tak jest.
Mike Zboray,
Działa zgodnie z oczekiwaniami! potrzebne do przekonwertowania Listy <object> na List <RealType>
Elo
20

Uważam, że coś takiego powinno działać:

origList.Select(a => new TargetType() { SomeValue = a.SomeValue});
Andy White
źródło
1
Musisz dodać .ToList()na końcu, w przeciwnym razie będzie to po prostu IEnumerable.
MattD
10

Oto prosty przykład ..

List<char> c = new List<char>() { 'A', 'B', 'C' };

List<string> s = c.Select(x => x.ToString()).ToList();
Ian P.
źródło
1
Niesamowite ... dokładnie to, czego szukałem! Cóż, niezupełnie dokładnie ... Chciałem tylko właściwości każdego elementu na liście, ale dałeś mi składnię Lamba bez konieczności przewijania zbyt daleko. ;)
błąd
7
var list1 = new List<Type1>();
var list2 = new List<Type2>();

list1.ForEach(item => list2.Add(new Type2() { Prop1 = value1 }));
Chris Arnold
źródło
3

Załóżmy, że masz wiele właściwości, które chcesz przekonwertować.

public class OrigType{
    public string Prop1A {get;set;}
    public string Prop1B {get;set;}
}

public class TargetType{
    public string Prop2A {get;set;}
    public string Prop2B {get;set;}
}

var list1 = new List<OrigType>();
var list2 = new List<TargetType>();

list1.ConvertAll(x => new OrigType { Prop2A = x.Prop1A, Prop2B = x.Prop1B })
Max Chu
źródło
2

Lub z constructor& linqz Select:

public class TargetType {
  public string Prop1 {get;set;}
  public string Prop1 {get;set;}

  // Constructor
  public TargetType(OrigType origType) {
    Prop1 = origType.Prop1;
    Prop2 = origType.Prop2;
  }
}

var origList = new List<OrigType>();
var targetList = origList.Select(s=> new TargetType(s)).ToList();  

LinqLinia jest bardziej miękka! ;-)

A. Morel
źródło
0

Jeśli potrzebujesz użyć funkcji do rzutowania:

var list1 = new List<Type1>();
var list2 = new List<Type2>();

list2 = list1.ConvertAll(x => myConvertFuntion(x));

Gdzie jest moja funkcja niestandardowa:

private Type2 myConvertFunction(Type1 obj){
   //do something to cast Type1 into Type2
   return new Type2();
}
jaimenino
źródło
0

dla podobnej klasy typu.

List<targetlist> targetlst= JsonConvert.DeserializeObject<List<targetlist>>(JsonConvert.SerializeObject(<List<baselist>));

Arun Solanki
źródło
Dziękuję Ci bardzo. Serwer jest drogi jak diabli i nie jest zgodny z najlepszymi praktykami, ale działa doskonale. Użyłem go do konwersji pierwszych klas bazy danych EF, gdy wiele procedur zwraca w rezultacie te same 5 kolumn, tylko dla różnych „klauzul where” w procedurach. Wiem, że powinienem
ustawić
-1

Jeśli typy można rzutować bezpośrednio, jest to najczystszy sposób:

var target = yourList.ConvertAll(x => (TargetType)x);

Jeśli typy nie mogą być rzutowane bezpośrednio, możesz odwzorować właściwości z typu oryginalnego na typ docelowy.

var target = yourList.ConvertAll(x => new TargetType { SomeValue = x.SomeValue });
Ayo Adesina
źródło
-1

Rozważymy, że pierwszy typ listy to String i chcemy przekonwertować go na liczbę całkowitą typu List.

List<String> origList = new ArrayList<>(); // assume populated

Dodaj wartości do oryginalnej listy.

origList.add("1");
origList.add("2");
    origList.add("3");
    origList.add("4");
    origList.add("8");

Utwórz listę docelową typu liczby całkowitej

List<Integer> targetLambdaList = new ArrayList<Integer>();
targetLambdaList=origList.stream().map(Integer::valueOf).collect(Collectors.toList());

Drukuj wartości listy za pomocą forEach:

    targetLambdaList.forEach(System.out::println);
garima garg
źródło