แปลงรายการวัตถุจากประเภทหนึ่งไปอีกประเภทหนึ่งโดยใช้การแสดงออกแลมบ์ดา


224

ฉันมีวง foreach อ่านรายการของวัตถุประเภทหนึ่งและผลิตรายการวัตถุประเภทอื่น ฉันถูกบอกว่าการแสดงออกแลมบ์ดาสามารถบรรลุผลลัพธ์เดียวกัน

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

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

ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชม - ฉันยังใหม่กับแลมบ์ดาและลินุกซ์ขอบคุณ


@ mmcrae คำถามนั้นใหม่กว่าคำถามนี้
Andy Wiesendanger

คำตอบ:


312

ลองทำสิ่งต่อไปนี้

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

นี่คือการใช้ Lambdas และ LINQ ร่วมกันเพื่อให้ได้โซลูชัน ฟังก์ชั่นเลือกเป็นวิธีการฉายสไตล์ซึ่งจะใช้การส่งผ่านเป็นตัวแทน (หรือแลมบ์ดาในกรณีนี้) กับทุกค่าในคอลเลกชันดั้งเดิม IEnumerable<TargetType>ผลที่จะได้รับกลับมาในใหม่ โทร .ToList เป็นวิธีขยายซึ่งจะแปลงนี้เป็น IEnumerable<TargetType>List<TargetType>


มีวิธีการทำเช่นนี้โดยไม่ต้องมีการนำไปใช้อย่างเป็นรูปธรรมTargetTypeหรือไม่? ฉันลงเอยด้วยสิ่งนี้: List<ISearchEntity> results = myIQueryable.Select(x => (ISearchEntity) new TargetType { MyField = "Field value is " + x.TargetField }).ToList();เป้าหมายคือเพื่อให้ได้วัตถุประเภทList<ISearchEntity>
Aaron Newton

220

หากคุณรู้ว่าคุณต้องการแปลงจากList<T1>เป็นList<T2>แล้วList<T>.ConvertAllจะมีประสิทธิภาพมากกว่าSelect/ ToListเพราะรู้ขนาดที่แน่นอนเริ่มต้นด้วย:

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

ในกรณีทั่วไปมากขึ้นเมื่อคุณรู้เกี่ยวกับแหล่งที่มาเป็นเพียงการIEnumerable<T>ใช้Select/ ToListเป็นวิธีที่จะไป คุณอาจโต้เถียงว่าในโลกที่มี LINQ มันเป็นสำนวนที่เริ่มต้นด้วย ... แต่มันก็คุ้มค่าอย่างน้อยเมื่อรู้ตัวConvertAllเลือก


1
ตอนแรกฉันไม่คิดว่าฉันจะทำเช่นนี้ได้เพราะฉันจัดการกับตัวเลขที่แจกแจง (สำหรับรายการแหล่งที่มาและมันไม่มีตัวเลือก convertall) ดังนั้นฉันจึงเรียกว่า. ToList () และตอนนี้ฉันกำลังพยายาม convertall - i ชอบที่จะดีกว่าการใส่ตัวกรองที่ไม่มี 'ที่ไหน'
Stratton

2
ทำไมคุณจะต้องอยู่ที่ไหน หากคุณเพิ่งได้รับIEnumerable<T>เพียงแค่โทรSelectและToListตามคำตอบของ Jared
Jon Skeet

สำหรับมือใหม่อื่น ๆ เช่นฉันคุณสามารถเรียกวิธีการเช่นx => buildTargetType(x)
Snekse

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

1
ไวยากรณ์นี้คืออะไร สิ่งนี้ไม่ได้ทำให้เกิดแลมบ์ดา ลิงค์เอกสารบางส่วนจะได้รับการชื่นชม ขอบคุณแม้ว่ามันใช้งานได้ดีที่นี่
Pierre de LESPINAY

อาร์กิวเมนต์ของ ConvertAll เป็น C # แลมบ์ดาใช่ไหม
avl_sweden

1
ดูดี แต่ต้องการบริบทบางอย่างเมื่อสามารถใช้ (หรือถ้า) ฉันเพิ่งลองและได้รับการcannot cast expressionยกเว้น
Collin M. Barrett

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

5
-1 สิ่งนี้จะใช้ได้ก็ต่อเมื่อการคัดเลือกนักแสดงเป็นไปได้และในกรณี OPs มันจะปรากฏขึ้น
Mike Zboray

ทำงานได้ตามคาด! จำเป็นต้องแปลง List <object> เป็น List <RealType>
Elo

20

ฉันเชื่อว่าสิ่งนี้ควรใช้งานได้:

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

1
คุณต้องเพิ่ม a .ToList()ท้ายมิฉะนั้นจะให้ IEnumerable
MattD

10

นี่คือตัวอย่างง่ายๆ ..

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

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

1
เยี่ยมมาก ... สิ่งที่ฉันกำลังมองหา! ไม่เหมือนกัน ... ฉันแค่ต้องการทรัพย์สินของแต่ละองค์ประกอบในรายการ แต่คุณให้ไวยากรณ์ lamba แก่ฉันโดยไม่ต้องเลื่อนไปไกลเกินไป ;)
ข้อผิดพลาด


3

สมมติว่าคุณมีคุณสมบัติหลายอย่างที่คุณต้องการแปลง

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

หรือด้วยconstructor& linqด้วย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();  

Linqเส้นนุ่มมากขึ้น! ;-)


0

หากคุณต้องการใช้ฟังก์ชันเพื่อส่ง:

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

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

หน้าที่ของฉันคือ:

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

0

สำหรับคลาสประเภทที่คล้ายกัน

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


ขอบคุณมาก. มันแพงพอ ๆ กับเซิร์ฟเวอร์และมันไม่ได้เป็นไปตามแนวทางปฏิบัติที่ดีที่สุด แต่ทำงานได้อย่างยอดเยี่ยม ฉันใช้มันเพื่อแปลงชั้นเรียนฐานข้อมูลของ EF เป็นครั้งแรกเมื่อโพรซีเดอร์หลายรายการส่งคืน 5 คอลัมน์เดียวกันเป็นผลลัพธ์เฉพาะสำหรับ "คำสั่ง" ที่แตกต่างกันในขั้นตอนเท่านั้น ฉันรู้ว่าฉันควรจะสร้างตารางในฐานข้อมูล แต่ฉันไม่ใช่ผู้ออกแบบ ..
jo1storm

-1

หากประเภทสามารถโยนโดยตรงนี่เป็นวิธีที่สะอาดที่สุดในการทำ:

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

หากไม่สามารถโยนประเภทโดยตรงคุณสามารถแมปคุณสมบัติจากประเภทเดิมไปยังประเภทเป้าหมาย

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

-1

เราจะพิจารณาชนิดของรายการแรกคือสตริงและต้องการแปลงเป็นประเภทรายการจำนวนเต็ม

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

เพิ่มค่าในรายการต้นฉบับ

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

สร้างรายการเป้าหมายของประเภทจำนวนเต็ม

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

พิมพ์ค่ารายการโดยใช้ forEach:

    targetLambdaList.forEach(System.out::println);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.