convertir une liste d'objets d'un type à un autre à l'aide de l'expression lambda

224

J'ai une boucle foreach qui lit une liste d'objets d'un type et produit une liste d'objets d'un type différent. On m'a dit qu'une expression lambda peut obtenir le même résultat.

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

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

Toute aide serait appréciée - je suis nouveau sur lambda et linq merci, s

Stratton
la source
@mmcrae cette question est plus récente que celle-ci
Andy Wiesendanger

Réponses:

312

Essayez ce qui suit

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

Cela utilise une combinaison de Lambdas et LINQ pour parvenir à la solution. La fonction Select est une méthode de style de projection qui appliquera le délégué passé (ou lambda dans ce cas) à chaque valeur de la collection d'origine. Le résultat sera retourné dans un nouveau IEnumerable<TargetType>. L'appel .ToList est une méthode d'extension qui le convertira IEnumerable<TargetType>en un List<TargetType>.

JaredPar
la source
Y a-t-il un moyen de le faire sans avoir une mise en œuvre concrète pour TargetType? Je me suis retrouvé avec quelque chose comme ça: List<ISearchEntity> results = myIQueryable.Select(x => (ISearchEntity) new TargetType { MyField = "Field value is " + x.TargetField }).ToList();où le but était d'obtenir un objet de typeList<ISearchEntity>
Aaron Newton
220

Si vous savez que vous souhaitez convertir à partir List<T1>de, List<T2>alors List<T>.ConvertAllsera légèrement plus efficace que Select/ ToListcar il connaît la taille exacte pour commencer:

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

Dans le cas plus général, lorsque vous ne connaissez la source qu'en tant que IEnumerable<T>, l'utilisation de Select/ ToListest la voie à suivre. Vous pourriez également faire valoir que dans un monde avec LINQ, c'est plus idiomatique pour commencer ... mais cela vaut au moins la peine d'être au courant de l' ConvertAlloption.

Jon Skeet
la source
1
au début, je ne pensais pas que je pouvais faire cela, parce que je faisais affaire avec un ienumerable (pour la liste source et il ne fournit pas d'option convertall) alors j'ai appelé .ToList () dessus et maintenant j'essaie convertall - je l'aime mieux que de mettre un "où" non filtrant
Stratton
2
Pourquoi auriez-vous besoin d'un endroit? Si vous avez seulement IEnumerable<T>alors appelez Selectet ToListselon la réponse de Jared.
Jon Skeet
Pour d'autres débutants comme moi, vous pouvez également appeler une méthode commex => buildTargetType(x)
Snekse
55
var target = origList.ConvertAll(x => (TargetType)x);
Alp
la source
1
Quelle est cette syntaxe? Cela ne ressemble pas à un lambda. Un lien de documentation serait apprécié. Merci cependant, cela fonctionne bien ici
Pierre de LESPINAY
L'argument de ConvertAll est un lambda C # normal, non?
avl_sweden
1
semble agréable, mais a besoin de contexte pour savoir quand (ou si) il peut être utilisé. Je viens de l'essayer et j'obtenais une cannot cast expressionexception
Collin M. Barrett
31
List<target> targetList = new List<target>(originalList.Cast<target>());
Pranav
la source
5
-1 cela ne fonctionnerait que si le casting était possible et dans le cas OP il semble qu'il en soit ainsi.
Mike Zboray
Fonctionne comme prévu! nécessaire pour convertir List <object> en List <RealType>
Elo
20

Je crois que quelque chose comme ça devrait fonctionner:

origList.Select(a => new TargetType() { SomeValue = a.SomeValue});
Andy White
la source
1
Vous devez ajouter un .ToList()à la fin, sinon cela fournira simplement un IEnumerable.
MattD
10

Voici un exemple simple ..

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

List<string> s = c.Select(x => x.ToString()).ToList();
Ian P
la source
1
Génial ... exactement ce que je cherchais! Eh bien, pas tout à fait exactement ... Je voulais juste une propriété de chaque élément de la liste, mais vous m'avez donné la syntaxe lamba sans avoir à trop défiler. ;)
erreur
7
var list1 = new List<Type1>();
var list2 = new List<Type2>();

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

Supposons que vous ayez plusieurs propriétés à 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 })
Max Chu
la source
2

Ou avec un constructor& linqavec 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 Linqligne est plus douce! ;-)

A. Morel
la source
0

Si vous devez utiliser une fonction pour caster:

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

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

Où est ma fonction personnalisée:

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

pour une classe de type similaire.

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

Arun Solanki
la source
Merci beaucoup. Il coûte cher pour le serveur et n'est pas conforme aux meilleures pratiques, mais fonctionne à merveille. Je l'ai utilisé pour convertir les premières classes de base de données EF lorsque plusieurs procédures retournent les mêmes 5 colonnes en conséquence, uniquement pour différentes "clauses where" dans les procédures. Je sais que j'aurais dû faire un type de table dans la base de données, mais je n'étais pas le concepteur de cela ..
jo1storm
-1

Si les types peuvent être directement convertis, c'est la façon la plus simple de le faire:

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

Si les types ne peuvent pas être directement castés, vous pouvez mapper les propriétés du type d'origine au type cible.

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

Nous considérerons que le premier type de List est String et nous voulons le convertir en type Integer de List.

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

Ajoutez des valeurs dans la liste d'origine.

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

Créer une liste cible de type entier

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

Imprimer les valeurs de liste à l'aide de forEach:

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