C# Linq — упорядочить IEnumerable по количеству идентичных свойств

#c# #linq #count #sql-order-by

Вопрос:

Я пытаюсь найти выражение Linq, в котором я могу упорядочить свои IEnumerable, состоящие из

строка Страна строка Город bool IsCapital

таким образом, в новом IEnumerable перечислены все объекты, но порядок

  1. Округ, но сначала страна с большинством городов в списке, затем страна со вторым по количеству записей и так далее
  2. Затем в городе

моя первая попытка-это

 IEnumerable allCities = new Enumerable { 
//initialize list
};

allCities = allCities
.OrderBy(x => x.Country)
.ThenBy(x.City);
 

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

Я ценю вашу помощь, заранее благодарю вас.

Мартин

Ответ №1:

Вы можете использовать метод Linq GroupBy() как:

 // 1. Group by country
// 2. Order descending by the count of each group
// 3. Select all objects of all groups (ordered) to a flat list
var result = cities
    .GroupBy(x => x.Country)
    .OrderByDescending(grp => grp.Count())
    .SelectMany(grp => grp.OrderBy(x => x.City))
    .ToList();
 

Этот список объектов:

 var cities = new List<MyObj>
{
    new MyObj { Country = "Germany", City = "Frankfurt" },
    new MyObj { Country = "Norway", City = "Oslo" },
    new MyObj { Country = "Italy", City = "Rome" },
    new MyObj { Country = "Germany", City = "Berlin" },
    new MyObj { Country = "Germany", City = "Munich" },
    new MyObj { Country = "France", City = "Paris" },
    new MyObj { Country = "Italy", City = "Milano" },
};
 

…дал бы результат:

Германия — Берлин
Германия — Франкфурт
Германия — Мюнхен
Италия — Милан
Италия — Рим
Норвегия — Осло
Франция — Париж

Ответ №2:

Для этого вам нужна концепция Counties with their zero or more Cities . Как только вы это сделаете, вы сможете упорядочить округа по количеству городов и упорядочить города по округам.

Результат: Упорядоченные округа (по убыванию числа городов), и каждый город упорядочен по названию

Если вы хотите сгладить это в комбинации [Округ, город, столица], вы можете использовать SelectMany для этого.

Сначала вы должны сгруппировать все товары по одному округу. Увы, вы забыли дать вашему [округу, городу, столице] название класса, поэтому я дам ему название GeographicalItem

 IEnumerable<GeographicalItem> inputData = ...
 

Составьте группы из Counties with their Cities :

 var result = inputData.GroupBy(geographicalItem => geographicalItem.County,

// parameter resultSelector: for every Country, with all geograhpicalItems in this
// country make one "Country with its cities"
(country, geographicalItemsInThisCountry) => new
{
    Country = country,
    Cities = geoghraphicalItemsInThisCountry.Select(geographicalItem => new
    {
        Name = geographicalItem.City,
        IsCapital = geograhpicalItem.IsCapital,
    })
    .OrderBy(city => city.Name)
    .ToList(),
})
 

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

Теперь закажите страны: Сначала страны с большинством городов:

Продолжение LINQ:

 .OrderByDescending(country => country.Cities.Count)
 

Результат: Сортированные страны, каждая страна со своими Отсортированными городами. Страна с наибольшим количеством городов на первом месте. Города внутри страны упорядочены по названиям.

Если вы хотите сгладить результат: используйте SelectMany:

 .SelectMany(county => country.Cities,

// parameter resultSelector: from every [country, city] combination make one new:
(country, city) => new
{
    Country = country,
    City = city.Name,
    IsCapital = city.IsCapital,
});