2010-11-05 3 views
0

Эта ситуация может быть намного сложнее, чем я хочу, но я все равно ее выдвигаю. Это для дизайна игрового типа.LINQ, Слияние списков с соответствующими «переопределениями»

Значения здесь жестко закодированы, но этого не будет в реальной среде.

В принципе, есть списки классов, известных как Interpreter, которые содержат соответствующую информацию для перевода других вещей по программному движку. Для них есть «макет» по умолчанию, но затем во многих особых случаях их нужно переопределить.

Одно решение состоит в том, чтобы иметь только каждый экземпляр в каждом списке (это выполнимо, но я действительно считаю его избыточным, и я думаю, что существует более чистое решение). Вместо этого я хочу «объединить» их, но уметь указывать свойство для использования в качестве «переопределения». (. Полный исходный код доступен на Pastie я бы поставил его здесь, но мне сказали, что положить, что много коды отпугивает человек от ответа на мои вопросы): 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 
    } 

В этой ситуации, объединенный список должен читаться как ...

[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 

Я знаю, как я мог бы достичь этого с помощью этого конкретного примера, конечно. Я могу просто написать метод, который проверяет значение оценки и т. Д. Но я хочу использовать более основанный на конвенциях подход, который я могу использовать несколько более сложным образом. У кого-нибудь есть идеи?

ответ

1

Чтобы получить результат вы описали, вы можете использовать этот метод следующим образом:

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

Я могу иметь логику неправильно для случая, когда один Sheet содержит различные Trait с, но вы не указали, как сделать вы хотите их комбинировать.

Кроме того, дизайн вашего кода довольно странный. Не каждая коллекция должна быть List<T>. Особенно в этом случае, когда использование Dictionary<K,V> было бы намного чище (и быстрее), чем при использовании Single().

EDIT

Для обновленной версии, мне нравится List основанное решение более чем LINQ один:

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

Вот решение LINQ вы просили для:

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

Я не могу использовать словари, потому что это неизбежно будет сериализоваться в базе данных, а Entity Framework в настоящее время не поддерживает Словари в настоящее время, а другие люди в моей группе не будут использовать nHibernate по разным причинам. – Ciel

+0

Это решает проблему, если на «расширенном» листе нет ничего первоначального. Но если расширенный лист имеет что-то дополнительное, он не получает эту информацию. – Ciel

+0

Я обновил его, чтобы быть более понятным. – Ciel

Смежные вопросы