У меня List<IGrouping<string,string>>
.
Возможно ли добавить новый элемент в этот список? Или, действительно, возможно создать какой-то объект IGrouping?
У меня List<IGrouping<string,string>>
.
Возможно ли добавить новый элемент в этот список? Или, действительно, возможно создать какой-то объект IGrouping?
Если вы действительно хотели создать свой собственный IGrouping<TKey, TElement>
, это простой интерфейс для реализации:
public class MyGrouping<TKey, TElement> : List<TElement>, IGrouping<TKey, TElement>
{
public TKey Key
{
get;
set;
}
}
Этот класс наследует от List<T>
и реализует интерфейс IGrouping
. Помимо требования быть IEnumerable
и IEnumerable<TElement>
(который удовлетворяет List<T>
), единственным свойством для реализации является Key
.
Здесь вы можете создать все MyGrouping<string, string>
, которые хотите, и добавить их в свой List<IGrouping<string,string>>
.
Как и в случае с .NET 4.0, в BCL не существует каких-либо публичных типов, которые реализуют интерфейс IGrouping<TKey, TElement>
, поэтому вы не сможете с легкостью "обновить".
Конечно, вам ничего не мешает:
IGrouping<TKey, TElement>
из запроса LINQ, такого как ToLookup
и GroupBy
, и добавления его/их в список.ToList()
в существующей последовательности групп (из ToLookup/GroupBy).Пример:
IEnumerable<Foo> foos = ..
var barsByFoo = foos.ToLookup(foo => foo.GetBar());
var listOfGroups = new List<IGrouping<Foo, Bar>>();
listOfGroups.Add(barsByFoo.First()); // a single group
listOfGroups.AddRange(barsByFoo.Take(3)); // multiple groups
Не понятно, почему вы хотели бы это сделать.
Вы также можете взломать группировку, не группируя что-либо в списке:
var listOfGroups = new[] { "a1", "a2", "b1" }
.GroupBy(x => x.Substring(0, 1))
.ToList();
// baz is not anything to do with foo or bar yet we group on it
var newGroup = new[] { "foo", "bar" }.GroupBy(x => "baz").Single();
listOfGroups.Add(newGroup);
listOfGroups
затем содержит:
a:
a1, a2
b:
b1
baz:
foo, bar
IGrouping<TKey, TElement> CreateGroup<TKey, TElement>(IEnumerable<TElement> theSeqenceToGroup, TKey valueForKey)
{
return theSeqenceToGroup.GroupBy(stg => valueForKey).FirstOrDefault();
}
var headers = from header in new[] {
new { Name = "One", List = new[] { "One 1", "One 2", "One 2" } },
new { Name = "Two", List = new[] { "Two 1", "Two 2", "Two 2" } }
} from value in header.List group value by header.Name;
Основываясь на ответе Давида, я создал следующий метод расширения, который создает экземпляр IGrouping<TKey, TElement>
из IEnumerable<TElement>
и ключ типа TKey
:
public static IGrouping<TKey, TElement> ToGroup<TKey, TElement>(
this IEnumerable<TElement> elements,
TKey keyValue)
{
return elements.GroupBy(_ => keyValue).FirstOrDefault();
}
Это можно назвать так:
var fruits = new [] { "Apples", "Bananas" };
var myFruitsGroup = fruits.ToGroup("fruitsKey");
Остерегайтесь того, что ToGroup()
может вернуть null
.
Я также создал дополнительный метод расширения GroupBy
:
public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, IEnumerable<TElement>> elementsSelector)
{
return source
.Select(s => elementsSelector(s)
.ToGroup(keySelector(s)))
.Where(g => g != default(IGrouping<TKey, TElement>));
}
Его можно использовать так:
var foodItems = new []
{
new { Category = "Fruits", Items = new [] { "Apples", "Bananas" } },
new { Category = "Vegetables", Items = new [] { "Tomatoes", "Broccoli" } },
};
var categoryGroups = foodItems.GroupBy(i => i.Category, i => i.Items);
Интерфейс IGrouping
предназначен для оператора GroupBy()
в LINQ. Обычно вы получаете объект IGrouping
из запроса LINQ с предложением group by
. Однако нет смысла иметь список группировок.