LINQ GroupBy, преобразовать один-в-один список в один-ко-многим - PullRequest
2 голосов
/ 24 февраля 2011

Это можно сделать миллионами способов ...

Проблема. У меня есть список серверов, принадлежащих стране.

В странах есть много серверов, так что это двухсторонняя навигация (я думаю, что это называется)

Теперь у меня есть список серверов с установленной страной, и я хочу сгруппировать их по странам, чтобы я мог получить противоположный список.

Список стран со всеми серверами, подключенными к ICollection of the Country (Серверы)

var groupBy = list.GroupBy(x => x.Country, x => x, (c, s) => new {c, s});
foreach (var country in groupBy)
{
}

Это почти даст мне желаемый результат, но теперь у меня есть 2 типа anon. C - страна, а S - список серверов.

Как я могу прикрепить список серверов к Коллекции объекта страны.

Классы выглядят так ... упрощенно.

public class Server
{
    public short SID { get; set; }
    public Country Country { get; set; }
}

public class Country
{
    public byte CID { get; set; }
    public ICollection<Server> Servers { get; set; }
}

Полагаю, можно создать новую страну с информацией, а затем добавить список серверов в конструктор ... но я думаю, что это излишне.

Ну ... это странно быть простым, но я здесь потерян.

Обновление

Мне нужно выбрать все серверы, которые удовлетворяют некоторому условию. Вот почему у меня есть список серверов со страной. Теперь мне просто нужно инвертировать список. Можно ли это сделать наоборот?

Сначала я использую шаблон репозитория с кодом EF 4. IRepository У меня есть только следующие методы с возможностью загружать свойства: Single, SingleOrDefault, Find and FindAll

Там нет ленивой нагрузки, все они возвращают ICollection или один T.

Ответы [ 3 ]

2 голосов
/ 24 февраля 2011

Звучит так, будто вы действительно хотите создать поиск из страны на серверы:

var lookup = servers.ToLookup(server => server.Country);

Если это не , что вы ищете, пожалуйста, дайте мне знать, как это не делает то, что вы хотите:)

По общему признанию, нет никакой гарантии, что каждый Country будет иметь все серверы в исходном списке, и это звучит так, как будто именно это различие и является проблемой.

Если ваш Server уже имеет набор Country, не можете ли вы предположить, что данные уже согласованы? Если нет, то должен ли Server действительно иметь CID вместо Country ссылки? Иметь свойство, которое будет иногда соответствовать «этому» объекту, а иногда нет (то есть гарантированно server.Country.Contains(server) вернет true или нет) - это уродливо ИМО.

РЕДАКТИРОВАТЬ: Хорошо, возможно, более хорошая альтернатива:

var query = servers.GroupBy(server => server.Country.CID);
                   .Select(g => new Country { CID = g.Key,
                                              Servers = g.ToList() });

Это почти то же самое, что и подход fermaref, но я явно использую Country.CID, чтобы избежать двух серверов с эквивалентными странами, не попавшими в одно ведро из-за потенциально нечетные правила равенства.

1 голос
/ 24 февраля 2011

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

Linq для запросов и имеет функциональный склад умагде вы генерируете новые экземпляры вместо того, чтобы изменять существующие экземпляры.

Если вы хотите изменить экземпляры, цикл foreach лучше:

List<Server> servers = GetServers();

foreach(Server server in servers)
{
  Country c = server.Country;
  c.Servers.Add(server);
}

Если вы должны использовать Linq:

List<Server> servers = GetServers();

foreach(IGrouping<Country, Server> g in servers.GroupBy(s => s.Country))
{
  Country c = g.Key;
  c.Servers = g.ToList();
}

Теперь мне просто нужно инвертировать список.

ILookup<Country, Server> lookup = servers.ToLookup(s => s.Country);
List<Country> countries = lookup.Select(g => g.Key).ToList();
foreach(Country c in countries)
{
  c.Servers = lookup[c].ToList();
}
return countries;
0 голосов
/ 24 февраля 2011

Если вы не можете гарантировать, что объект Country в каждом объекте Server уже содержит все серверы, вы можете создать новый объект Country:

var groupBy = list.GroupBy(
                    x => x.Country, 
                    x => x, (c, s) => 
                                new Country 
                                {
                                  CID = c.CID, 
                                  Servers =  s.ToList()});

Однако яЯ не уверен, что это то, что вам нужно.

Если вы можете гарантировать, что объект Country всегда будет содержать все Servers, вы можете использовать следующее:

var countries = list.SelectMany(s => s.Country).Distinct();

или, если ваш Country не реализует IEquateable:

var groupBy = list.GroupBy(x => x.Country).Select(x => x.Key);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...