mengonversi daftar objek dari satu jenis ke yang lain menggunakan ekspresi lambda

224

Saya memiliki loop foreach membaca daftar objek dari satu jenis dan menghasilkan daftar objek dari jenis yang berbeda. Saya diberitahu bahwa ekspresi lambda dapat mencapai hasil yang sama.

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

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

Setiap bantuan akan dihargai - saya baru untuk lambda dan LINQ terima kasih, s

Stratton
sumber
@mmcrae pertanyaan itu lebih baru dari yang ini
Andy Wiesendanger

Jawaban:

312

Coba yang berikut ini

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

Ini menggunakan kombinasi Lambdas dan LINQ untuk mencapai solusi. Fungsi Select adalah metode gaya proyeksi yang akan menerapkan delegasi yang disahkan (atau lambda dalam kasus ini) untuk setiap nilai dalam koleksi asli. Hasilnya akan dikembalikan dalam yang baru IEnumerable<TargetType>. Panggilan .ToList adalah metode ekstensi yang akan mengubahnya IEnumerable<TargetType>menjadi List<TargetType>.

JaredPar
sumber
Apakah ada cara untuk melakukan ini tanpa memiliki implementasi konkret TargetType? Saya berakhir dengan sesuatu seperti ini: di List<ISearchEntity> results = myIQueryable.Select(x => (ISearchEntity) new TargetType { MyField = "Field value is " + x.TargetField }).ToList();mana tujuannya adalah untuk mendapatkan objek bertipeList<ISearchEntity>
Aaron Newton
220

Jika Anda tahu Anda ingin mengonversi dari List<T1>ke List<T2>maka List<T>.ConvertAllakan sedikit lebih efisien daripada Select/ ToListkarena ia tahu ukuran pasti untuk memulai dengan:

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

Dalam kasus yang lebih umum ketika Anda hanya tahu tentang sumbernya sebagai IEnumerable<T>, menggunakan Select/ ToListadalah cara untuk pergi. Anda juga bisa berargumen bahwa di dunia dengan LINQ, itu lebih idiomatis untuk memulai dengan ... tapi ada baiknya setidaknya menyadari ConvertAllopsi.

Jon Skeet
sumber
1
pada awalnya saya tidak berpikir saya bisa melakukan ini, karena saya berurusan dengan ienumerable (untuk daftar sumber dan itu tidak memberikan opsi convertall) jadi saya memanggil .ToList () di atasnya dan sekarang saya mencoba convertall - i seperti itu lebih baik daripada meletakkan di non-filtering 'di mana'
Stratton
2
Mengapa Anda membutuhkan tempat? Jika Anda baru saja mendapatkannya IEnumerable<T>maka panggil saja Selectdan ToListsesuai jawaban Jared.
Jon Skeet
Untuk pemula lainnya seperti saya, Anda juga dapat memanggil metode sepertix => buildTargetType(x)
Snekse
55
var target = origList.ConvertAll(x => (TargetType)x);
Puncak gunung
sumber
1
Apa sintaks ini? Ini bukan ressemble lambda. Beberapa tautan dokumentasi akan dihargai. Terima kasih, itu bekerja dengan baik di sini
Pierre de LESPINAY
Argumen untuk ConvertAll adalah C # lambda biasa, kan?
avl_sweden
1
terlihat bagus, tetapi membutuhkan beberapa konteks sekitar kapan (atau jika) itu dapat digunakan. Saya baru saja mencobanya dan mendapat cannot cast expressionpengecualian
Collin M. Barrett
31
List<target> targetList = new List<target>(originalList.Cast<target>());
Pranav
sumber
5
-1 ini hanya akan berfungsi jika casting dimungkinkan dan dalam kasus OPs tampaknya memang demikian.
Mike Zboray
Bekerja seperti yang diharapkan! diperlukan untuk mengonversi List <object> ke List <RealType>
Elo
20

Saya percaya sesuatu seperti ini harus bekerja:

origList.Select(a => new TargetType() { SomeValue = a.SomeValue});
Andy White
sumber
1
Anda harus menambahkan .ToList()di akhir, jika tidak, ini hanya akan memberikan jumlah IEnumerable.
MattD
10

Ini contoh sederhana ..

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

List<string> s = c.Select(x => x.ToString()).ToList();
Ian P
sumber
1
Luar biasa ... persis apa yang saya cari! Ya tidak persis ... Saya hanya ingin properti dari setiap Elemen dalam daftar, tetapi Anda memberi saya sintaks lamba tanpa harus menggulir terlalu jauh. ;)
erroric
7
var list1 = new List<Type1>();
var list2 = new List<Type2>();

list1.ForEach(item => list2.Add(new Type2() { Prop1 = value1 }));
Chris Arnold
sumber
3

Asumsikan bahwa Anda memiliki beberapa properti yang ingin Anda konversi.

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
sumber
2

Atau dengan a constructor& linqdengan 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();  

The Linqgaris lebih lembut! ;-)

A. Morel
sumber
0

Jika Anda perlu menggunakan fungsi untuk melakukan casting:

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

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

Di mana fungsi khusus saya:

private Type2 myConvertFunction(Type1 obj){
   //do something to cast Type1 into Type2
   return new Type2();
}
jaimenino
sumber
0

untuk kelas sejenis.

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

Arun Solanki
sumber
Terima kasih banyak. Mahal untuk server dan tidak sesuai dengan praktik terbaik, tetapi berfungsi dengan baik. Saya menggunakannya untuk mengkonversi kelas basis data EF ketika beberapa prosedur mengembalikan 5 kolom yang sama sebagai hasilnya, hanya untuk "klausa klausa" yang berbeda dalam prosedur. Saya tahu saya seharusnya membuat tipe tabel pada database, tapi saya bukan desainernya ..
jo1storm
-1

Jika jenis dapat dilemparkan langsung, ini adalah cara paling bersih untuk melakukannya:

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

Jika jenis tidak dapat secara langsung dilemparkan maka Anda dapat memetakan properti dari jenis asli ke jenis target.

var target = yourList.ConvertAll(x => new TargetType { SomeValue = x.SomeValue });
Ayo Adesina
sumber
-1

Kami akan mempertimbangkan jenis Daftar pertama adalah String dan ingin mengubahnya menjadi tipe Daftar Integer.

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

Tambahkan nilai dalam Daftar asli.

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

Buat daftar target Tipe Integer

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

Nilai Daftar Cetak menggunakan forEach:

    targetLambdaList.forEach(System.out::println);
garima garg
sumber