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


@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>.


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.


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

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>());

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

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();

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

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

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! ;-)


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

0

pour une classe de type similaire.

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


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

-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);
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.