2010-11-05 4 views
0

Cette situation peut être bien plus compliquée que je ne le souhaite, mais je la présente de toute façon. Ceci est pour un design de type jeu.LINQ, fusionner les listes avec les 'remplacements' appropriés

Les valeurs ici sont codées en dur, mais ce ne sera pas le cas dans un environnement réel.

Fondamentalement, il existe des listes de classes appelées Interpreter qui contiennent les informations appropriées pour traduire d'autres choses dans le moteur de programme. Il y a une 'disposition' par défaut pour ceux-ci, mais dans de nombreux cas particuliers, certains d'entre eux doivent être remplacés. Une solution consiste à avoir juste chaque instance dans chaque liste (c'est faisable, mais je pense vraiment que c'est redondant et je pense qu'une solution plus propre existe) Au lieu de cela, je veux les "combiner", mais être capable de spécifier un propriété à utiliser comme "override". (. Plein code source disponible sur pastie je mettrais ici, mais on m'a dit que mettre ce code beaucoup dissuade les gens de répondre à mes questions): http://www.pastie.org/1276064

public class Program 
{ 
    static void Main() 
    { 
     var traits = new List<Trait> 
     { 
      new Trait { Name = "Intellect" }, 
      new Trait { Name = "Strength" }, 
      new Trait { Name = "Constitution" } 
     }; 

     var scores = new List<Score> 
     { 
      new Score { Name = "Beginner", Rank = 1 }, 
      new Score { Name = "Adept", Rank = 2 }, 
      new Score { Name = "Expert", Rank = 3 }, 
      new Score { Name = "Master", Rank = 4 } 
     }; 

     // one sheet will have defaults 
     var initial = new Sheet 
     { 
      Interpreters = new List<Interpreter> 
      { 
       new Interpreter 
       { 
        Trait = traits.Single(s => s.Name == "Intellect"), 
        Score = scores.Single(s => s.Rank == 1), 
        Requirement = 10 
       }, 
       new Interpreter 
       { 
        Trait = traits.Single(s => s.Name == "Intellect"), 
        Score = scores.Single(s => s.Rank == 2), 
        Requirement = 20 
       }, 
       new Interpreter 
       { 
        Trait = traits.Single(s => s.Name == "Intellect"), 
        Score = scores.Single(s => s.Rank == 3), 
        Requirement = 30 
       } 
      } 
     }; 

     // other sheets will override some or all of the default 
     var advanced = new Sheet 
     { 
      Interpreters = new List<Interpreter> 
      { 
       new Interpreter 
       { 
        Trait = traits.Single(s => s.Name == "Intellect"), 
        Score = scores.Single(s => s.Rank == 2), 
        Requirement = 15 
       }, 
       new Interpreter 
       { 
        Trait = traits.Single(s => s.Name == "Intellect"), 
        Score = scores.Single(s => s.Rank == 4), 
        Requirement = 35 
       } 
      } 
     }; 

     // combined sheet should have values of default, with the appropriately 'overridden' values of the advanced 
    } 

Dans cette situation, devrait lire la liste combinée comme ...

[0] 
Trait = Intellect, 
Score = 1, 
Requirement = 10 
[1] 
Trait = Intellect, 
Score = 2, 
Requirement = 15 
[2] 
Trait = Intellect, 
Score = 3, 
Requirement = 30 
[3] 
Trait = Intellect, 
Score = 4, 
Requirement = 35 

Je sais comment je pourrais y arriver avec cette instance bien sûr. Je peux simplement écrire une méthode qui vérifie la valeur de la partition, etc. Mais je veux une approche plus conventionnelle que je peux utiliser d'une manière un peu plus compliquée. Quelqu'un a-t-il une idée?

Répondre

1

Pour obtenir le résultat que vous décrit, vous pouvez utiliser une méthode comme ceci:

Sheet Combine(Sheet initial, Sheet advanced) 
{ 
    Sheet result = new Sheet(); 
    result.Interpreters = new List<Interpreter>(
     initial.Interpreters.Select(i => 
      advanced.Interpreters.SingleOrDefault(a => a.Score == i.Score) ?? i) 
     ); 
    return result; 
} 

je peut avoir la logique erronée dans le cas où l'un Sheet contient différents Trait s, mais vous ne précise pas comment faire vous voulez les combiner.

En outre, la conception de votre code est assez étrange. Toutes les collections ne doivent pas nécessairement être un List<T>. Surtout dans ce cas, où utiliser Dictionary<K,V> serait beaucoup plus propre (et plus rapide) que d'utiliser Single().

EDIT

Pour votre version mise à jour, j'aime List solution à base de plus d'un LINQ un:

Sheet Combine(Sheet initial, Sheet advanced) 
{ 
    var interpreters = new List<Interpreter>(initial.Interpreters); 
    foreach (var interpreter in advanced.Interpreters) 
    { 
    int index = interpreters.FindIndex(x => x.Score == interpreter.Score); 
    if (index < 0) 
     interpreters.Add(interpreter); 
    else 
     interpreters[index] = interpreter; 
    } 

    return new Sheet { Interpreters = interpreters }; 
} 

EDIT 2

Voici la solution LINQ vous avez demandé pour:

Sheet Combine(Sheet initial, Sheet advanced) 
{ 
    var scores = initial.Interpreters.Select(i => i.Score) 
    .Concat(advanced.Interpreters.Select(i => i.Score)) 
    .Distinct().OrderBy(i => i); 
    var interpreters = scores.Select(s => 
    advanced.Interpreters.SingleOrDefault(i => i.Score == s) 
    ?? initial.Interpreters.Single(i => i.Score == s)); 
    return new Sheet { Interpreters = interpreters }; 
} 
+0

Je ne peux pas utiliser les dictionnaires car ceux-ci seront inévitablement sérialisés dans une base de données, et Entity Framework ne prend pas correctement en charge les dictionnaires, et les autres membres de mon groupe n'utiliseront pas nHibernate pour diverses raisons. – Ciel

+0

Cela résout le problème tant que la feuille «avancée» n'a rien que le premier fait. Mais si la feuille avancée a quelque chose en plus, elle n'obtient pas cette information. – Ciel

+0

Je l'ai mis à jour pour être un peu plus clair. – Ciel