convertir una lista de objetos de un tipo a otro usando la expresión lambda


224

Tengo un bucle foreach que lee una lista de objetos de un tipo y produce una lista de objetos de un tipo diferente. Me dijeron que una expresión lambda puede lograr el mismo resultado.

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

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

Cualquier ayuda sería apreciada, soy nuevo en lambda y linq gracias, s


@mmcrae esa pregunta es más nueva que esta
Andy Wiesendanger el

Respuestas:


312

Intenta lo siguiente

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

Esto está utilizando una combinación de Lambdas y LINQ para lograr la solución. La función Seleccionar es un método de estilo de proyección que aplicará el delegado pasado (o lambda en este caso) a todos los valores de la colección original. El resultado será devuelto en un nuevo IEnumerable<TargetType>. La llamada .ToList es un método de extensión que lo convertirá IEnumerable<TargetType>en un List<TargetType>.


¿Hay alguna manera de hacer esto sin tener una implementación concreta TargetType? Terminé con algo como esto: List<ISearchEntity> results = myIQueryable.Select(x => (ISearchEntity) new TargetType { MyField = "Field value is " + x.TargetField }).ToList();donde el objetivo era obtener un objeto de tipoList<ISearchEntity>
Aaron Newton

220

Si sabe que desea convertir de List<T1>a, List<T2>entonces List<T>.ConvertAllserá un poco más eficiente que Select/ ToListporque sabe el tamaño exacto para comenzar:

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

En el caso más general, cuando solo conoces la fuente como un IEnumerable<T>, usar Select/ ToListes el camino a seguir. También podría argumentar que en un mundo con LINQ, es más idiomático comenzar ... pero al menos vale la pena conocer la ConvertAllopción.


1
al principio no pensé que podría hacer esto, porque estaba lidiando con un número innumerable (para la lista de origen y no proporciona una opción de conversión), así que llamé a .ToList () y ahora estoy tratando de convertir todo - i me gusta más que poner un 'dónde' sin filtro
Stratton

2
¿Por qué necesitarías un dónde? Si solo tienes IEnumerable<T>, simplemente llama Selecty ToListsegún la respuesta de Jared.
Jon Skeet

Para otros novatos como yo, también puedes llamar a un método comox => buildTargetType(x)
Snekse

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

1
¿Qué es esta sintaxis? Esto no se parece a una lambda. Se agradecería algún enlace de documentación. Gracias, sin embargo, funciona bien aquí
Pierre de LESPINAY

El argumento para ConvertAll es una lambda C # normal, ¿verdad?
avl_sweden

1
se ve bien, pero necesita algo de contexto cuando (o si) se puede usar. Lo intenté y recibí una cannot cast expressionexcepción
Collin M. Barrett, el

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

55
-1 esto solo funcionaría si fuera posible la conversión y en el caso de los OP parece ser así.
Mike Zboray

Funciona como se esperaba! necesario para convertir List <object> en List <RealType>
Elo

20

Creo que algo como esto debería funcionar:

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

1
.ToList()Debe agregar un al final, de lo contrario, esto simplemente proporcionará un IEnumerable.
MattD

10

Aquí hay un ejemplo simple ...

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

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

1
Impresionante ... ¡exactamente lo que estaba buscando! Bueno, no exactamente ... Solo quería una propiedad de cada Elemento en la lista, pero me diste la sintaxis de lamba sin tener que desplazarte demasiado. ;)
error

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

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

3

Suponga que tiene varias propiedades que desea convertir.

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

O con un constructor& linqcon 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();  

¡La Linqlínea es más suave! ;-)


0

Si necesita usar una función para emitir:

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

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

Donde mi función personalizada es:

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

0

para una clase de tipo similar.

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


Muchas gracias. Es caro como el infierno para el servidor y no está de acuerdo con las mejores prácticas, pero funciona espléndidamente. Lo usé para convertir las primeras clases de la base de datos EF cuando múltiples procedimientos devuelven las mismas 5 columnas como resultado, solo para diferentes "cláusulas where" en los procedimientos. Sé que debería haber hecho el tipo de tabla en la base de datos, pero no fui el diseñador de eso ...
jo1storm

-1

Si los tipos se pueden lanzar directamente, esta es la forma más limpia de hacerlo:

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

Si los tipos no se pueden emitir directamente, puede asignar las propiedades del tipo original al tipo de destino.

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

-1

Consideraremos que el primer tipo de Lista es Cadena y queremos convertirlo en un tipo de Lista Entero.

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

Agregar valores en la lista original.

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

Crear lista de destino de tipo entero

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

Imprimir los valores de la lista con forEach:

    targetLambdaList.forEach(System.out::println);
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.