converter uma lista de objetos de um tipo para outro usando a expressão lambda


224

Eu tenho um loop foreach lendo uma lista de objetos de um tipo e produzindo uma lista de objetos de um tipo diferente. Disseram-me que uma expressão lambda pode alcançar o mesmo resultado.

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

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

Qualquer ajuda seria apreciada- eu sou novo no lambda e linq obrigado, s


@mmcrae essa pergunta é mais recente que esta
217 Andy Wiesendanger

Respostas:


312

Tente o seguinte

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

Isso está usando uma combinação de Lambdas e LINQ para obter a solução. A função Selecionar é um método de estilo de projeção que aplicará o delegado passado (ou lambda nesse caso) a todos os valores da coleção original. O resultado será retornado em um novo IEnumerable<TargetType>. A chamada .ToList é um método de extensão que o converterá IEnumerable<TargetType>em um List<TargetType>.


Existe uma maneira de fazer isso sem ter uma implementação concreta TargetType? Eu acabei com algo como isto: List<ISearchEntity> results = myIQueryable.Select(x => (ISearchEntity) new TargetType { MyField = "Field value is " + x.TargetField }).ToList();onde o objetivo era fazer com que um objeto do tipoList<ISearchEntity>
Aaron Newton

220

Se você sabe que deseja converter de List<T1>para List<T2>então, List<T>.ConvertAllserá um pouco mais eficiente que Select/ ToListporque sabe o tamanho exato para começar:

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

No caso mais geral, quando você conhece apenas a fonte como uma IEnumerable<T>, usar Select/ ToListé o caminho a percorrer. Você também pode argumentar que, em um mundo com LINQ, é mais idiomático para começar ... mas vale a pena pelo menos estar ciente da ConvertAllopção.


1
no começo eu não achei que poderia fazer isso, porque estava lidando com um ienumerable (para a lista de fontes e ele não fornece uma opção convertall), então chamei .ToList () e agora estou tentando o convertall - i como se melhor do que colocar em um não-filtragem 'onde'
Stratton

2
Por que você precisaria de onde? Se você só tem IEnumerable<T>, basta ligar Selecte de ToListacordo com a resposta de Jared.
Jon Skeet

Para outros iniciantes como eu, você também pode chamar um método comox => buildTargetType(x)
Snekse

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

1
Qual é essa sintaxe? Isso não se assemelha a um lambda. Algum link de documentação seria apreciado. Graças, porém, ele funciona muito bem aqui
Pierre de LESPINAY

O argumento para ConvertAll é um lambda C # regular, certo?
precisa saber é

1
parece bom, mas precisa de algum contexto sobre quando (ou se) ele pode ser usado. Eu apenas tentei e estava recebendo uma cannot cast expressionexceção
Collin M. Barrett

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

5
-1 isso só funcionaria se a transmissão fosse possível e, no caso dos OPs, parece que sim.
Mike Zboray

Funciona como esperado! necessário para converter List <object> em List <RealType>
Elo

20

Eu acredito que algo assim deve funcionar:

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

1
Você precisa adicionar um .ToList()no final, caso contrário, isso simplesmente fornecerá um IEnumerable.
MattD

10

Aqui está um exemplo simples ..

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

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

1
Incrível ... exatamente o que eu estava procurando! Bem, não exatamente ... Eu só queria uma propriedade de cada elemento na lista, mas você me deu a sintaxe do lamba sem precisar rolar muito longe. ;)
erroric

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

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

3

Suponha que você tenha várias propriedades que deseja converter.

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

Ou com um constructore linqcom 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();  

A Linqlinha é mais suave! ;-)


0

Se você precisar usar uma função para transmitir:

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

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

Onde minha função personalizada é:

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

0

para classe de tipo semelhante.

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


Muito obrigado. É caro demais para o servidor e não está de acordo com as melhores práticas, mas funciona esplendidamente. Usei-o para converter as primeiras classes do banco de dados EF quando vários procedimentos retornam as mesmas 5 colunas como resultado, apenas para diferentes "cláusulas where" nos procedimentos. Eu sei que deveria ter criado o tipo de tabela no banco de dados, mas não fui o criador disso ..
jo1storm 23/03

-1

Se os tipos puderem ser convertidos diretamente, é a maneira mais limpa de fazer isso:

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

Se os tipos não puderem ser convertidos diretamente, você poderá mapear as propriedades do tipo original para o tipo de destino.

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

-1

Vamos considerar que o primeiro tipo de lista é String e queremos convertê-lo para o tipo inteiro da lista.

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

Adicione valores na lista original.

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

Criar lista de destino do tipo inteiro

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

Imprimir valores da lista usando forEach:

    targetLambdaList.forEach(System.out::println);
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.