chuyển đổi danh sách các đối tượng từ loại này sang loại khác bằng biểu thức lambda


224

Tôi có một vòng lặp foreach đọc một danh sách các đối tượng của một loại và tạo ra một danh sách các đối tượng thuộc một loại khác. Tôi đã nói rằng một biểu thức lambda có thể đạt được kết quả tương tự.

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

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

Bất kỳ trợ giúp sẽ được đánh giá cao - tôi mới đến lambda và linq cảm ơn, s


@mmcrae câu hỏi đó mới hơn câu hỏi này
Andy Wiesendanger

Câu trả lời:


312

Hãy thử như sau

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

Điều này là sử dụng kết hợp Lambdas và LINQ để đạt được giải pháp. Hàm Chọn là một phương thức kiểu chiếu sẽ áp dụng hàm được truyền trong ủy nhiệm (hoặc lambda trong trường hợp này) cho mọi giá trị trong bộ sưu tập gốc. Kết quả sẽ được trả lại trong một mới IEnumerable<TargetType>. Cuộc gọi .ToList là một phương thức mở rộng sẽ chuyển đổi nó IEnumerable<TargetType>thành một List<TargetType>.


Có cách nào để làm điều này mà không cần phải thực hiện cụ thể TargetTypekhông? Tôi đã kết thúc với một thứ như thế này: List<ISearchEntity> results = myIQueryable.Select(x => (ISearchEntity) new TargetType { MyField = "Field value is " + x.TargetField }).ToList();mục tiêu là lấy một vật thể loạiList<ISearchEntity>
Aaron Newton

220

Nếu bạn biết bạn muốn chuyển đổi từ List<T1>để List<T2>sau đó List<T>.ConvertAllsẽ hơi hiệu quả hơn Select/ ToListbởi vì nó biết kích thước chính xác để bắt đầu với:

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

Trong trường hợp tổng quát hơn khi bạn chỉ biết về nguồn là một IEnumerable<T>, sử dụng Select/ ToListlà cách để đi. Bạn cũng có thể lập luận rằng trong một thế giới có LINQ, việc bắt đầu bằng ... nhưng ít nhất cũng đáng để ý đến ConvertAlltùy chọn này.


1
Lúc đầu tôi không nghĩ mình có thể làm điều này, vì tôi đã giao dịch với một số lượng lớn (cho danh sách nguồn và nó không cung cấp tùy chọn convertall) nên tôi đã gọi .ToList () trên đó và bây giờ tôi đang thử convertall - i thích nó hơn là đưa vào một "không lọc"
Stratton

2
Tại sao bạn cần một nơi? Nếu bạn chỉ nhận được IEnumerable<T>thì chỉ cần gọi SelectToListtheo câu trả lời của Jared.
Jon Skeet

Đối với những người mới khác như tôi, bạn cũng có thể gọi một phương thức nhưx => buildTargetType(x)
Snekse

55
var target = origList.ConvertAll(x => (TargetType)x);

1
Cú pháp này là gì? Điều này không giống với lambda. Một số liên kết tài liệu sẽ được đánh giá cao. Dù vậy, cảm ơn, nó hoạt động tốt ở đây
Pierre de LESPINAY

Đối số của ConvertAll là C # lambda thông thường, phải không?
avl_sweden

1
trông đẹp, nhưng cần một số bối cảnh xung quanh khi (hoặc nếu) nó có thể được sử dụng. Tôi vừa thử nó và nhận được một cannot cast expressionngoại lệ
Collin M. Barrett

31
List<target> targetList = new List<target>(originalList.Cast<target>());

5
-1 điều này sẽ chỉ hoạt động nếu có thể truyền và trong trường hợp OP, nó có vẻ như vậy.
Mike Zboray

Hoạt động như mong đợi! cần thiết để chuyển đổi Danh sách <đối tượng> thành Danh sách <RealType>
Elo

20

Tôi tin rằng một cái gì đó như thế này sẽ hoạt động:

origList.Select(a => new TargetType() { SomeValue = a.SomeValue});

1
Bạn cần thêm một .ToList()ở cuối, nếu không điều này sẽ chỉ cung cấp một IEnumerable.
MattD

10

Đây là một ví dụ đơn giản ..

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

List<string> s = c.Select(x => x.ToString()).ToList();

1
Tuyệt vời ... chính xác những gì tôi đang tìm kiếm! Cũng không hoàn toàn chính xác ... Tôi chỉ muốn một thuộc tính của từng Element trong danh sách, nhưng bạn đã cho tôi cú pháp lamba mà không cần phải di chuyển quá xa. ;)
lỗi

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

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

3

Giả sử rằng bạn có nhiều thuộc tính bạn muốn chuyển đổi.

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 })

2

Hoặc với một constructor& linqvới 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();  

Các Linqdòng là mềm hơn! ;-)


0

Nếu bạn cần sử dụng một chức năng để truyền:

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

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

Chức năng tùy chỉnh của tôi là:

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

0

cho lớp loại tương tự.

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


Cảm ơn rât nhiều. Nó là đắt như địa ngục cho máy chủ và nó không theo thông lệ tốt nhất, nhưng hoạt động tuyệt vời. Tôi đã sử dụng nó để chuyển đổi các lớp cơ sở dữ liệu EF đầu tiên khi nhiều thủ tục trả về cùng 5 cột, chỉ cho các "mệnh đề" khác nhau trong các thủ tục. Tôi biết tôi nên tạo kiểu bảng trên cơ sở dữ liệu, nhưng tôi không phải là người thiết kế nó ..
jo1storm

-1

Nếu các loại có thể được đúc trực tiếp thì đây là cách sạch nhất để làm điều đó:

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

Nếu các loại không thể được truyền trực tiếp thì bạn có thể ánh xạ các thuộc tính từ loại ban đầu sang loại mục tiêu.

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

-1

Chúng tôi sẽ xem loại Danh sách đầu tiên là Chuỗi và muốn chuyển đổi thành Loại Danh sách Số nguyên.

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

Thêm giá trị trong Danh sách gốc.

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

Tạo mục tiêu Danh sách loại số nguyên

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

In giá trị danh sách bằng cách sử dụng forEach:

    targetLambdaList.forEach(System.out::println);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.