Есть ли метод Linq для добавления одного элемента в IEnumerable <T>?
В основном я пытаюсь сделать что-то вроде этого:
image.Layers
который возвращает IEnumerable для всех слоев, кроме слоя Parent
, но в некоторых случаях я просто хочу:
image.Layers.With(image.ParentLayer);
потому что он используется только в нескольких местах по сравнению с 100 обычным использованием, удовлетворяемым image.Layers
. Поэтому я не хочу создавать другое свойство, которое также возвращает слой Parent
.
Ответы
Ответ 1
Один из способов - создать одиночную последовательность из элемента (например, массив), а затем Concat
на оригинал:
image.Layers.Concat(new[] { image.ParentLayer } )
Если вы делаете это очень часто, подумайте о том, чтобы написать Append
(или аналогичный) метод расширения, такой как указанный здесь, что позволит вы делаете:
image.Layers.Append(image.ParentLayer)
Ответ 2
Уже реализовано много реализаций.
Моя выглядит немного по-другому (но так же хорошо)
Кроме того, я считаю целесообразным использовать одно и то же имя (Concat). Это означает, что вам нужно явно указать спецификатор типа при работе с IEnumerables из IEnumerables, но в моих проектах, которые не происходят слишком часто.
Кроме того, я нахожу его практическим, чтобы также иметь контроль над ORDER. поэтому часто у меня также есть метод ConcatTo, который помещает новый элемент вперед.
public static class Utility
{
/// <summary>
/// Adds the specified element at the end of the IEnummerable.
/// </summary>
/// <typeparam name="T">The type of elements the IEnumerable contans.</typeparam>
/// <param name="target">The target.</param>
/// <param name="item">The item to be concatenated.</param>
/// <returns>An IEnumerable, enumerating first the items in the existing enumerable</returns>
public static IEnumerable<T> ConcatItem<T>(this IEnumerable<T> target, T item)
{
if (null == target) throw new ArgumentException(nameof(target));
foreach (T t in target) yield return t;
yield return item;
}
/// <summary>
/// Inserts the specified element at the start of the IEnumerable.
/// </summary>
/// <typeparam name="T">The type of elements the IEnumerable contans.</typeparam>
/// <param name="target">The IEnummerable.</param>
/// <param name="item">The item to be concatenated.</param>
/// <returns>An IEnumerable, enumerating first the target elements, and then the new element.</returns>
public static IEnumerable<T> ConcatTo<T>(this IEnumerable<T> target, T item)
{
if (null == target) throw new ArgumentException(nameof(target));
yield return item;
foreach (T t in target) yield return t;
}
}
Или, наоборот, используйте неявно созданный массив. (используя ключевое слово params), чтобы вы могли вызвать метод для добавления одного или нескольких элементов за раз:
public static class Utility
{
/// <summary>
/// Adds the specified element at the end of the IEnummerable.
/// </summary>
/// <typeparam name="T">The type of elements the IEnumerable contans.</typeparam>
/// <param name="target">The target.</param>
/// <param name="items">The items to be concatenated.</param>
/// <returns>An IEnumerable, enumerating first the items in the existing enumerable</returns>
public static IEnumerable<T> ConcatItems<T>(this IEnumerable<T> target, params T[] items) =>
(target ?? throw new ArgumentException(nameof(target))).Concat(items);
/// <summary>
/// Inserts the specified element at the start of the IEnumerable.
/// </summary>
/// <typeparam name="T">The type of elements the IEnumerable contans.</typeparam>
/// <param name="target">The IEnummerable.</param>
/// <param name="items">The items to be concatenated.</param>
/// <returns>An IEnumerable, enumerating first the target elements, and then the new elements.</returns>
public static IEnumerable<T> ConcatTo<T>(this IEnumerable<T> target, params T[] items) =>
items.Concat(target ?? throw new ArgumentException(nameof(target)));
Ответ 3
Не существует единого метода, который делает это. Самый близкий метод Enumerable.Concat
, но он пытается объединить IEnumerable<T>
с другим IEnumerable<T>
. Вы можете использовать следующее, чтобы заставить его работать с одним элементом
image.Layers.Concat(new [] { image.ParentLayer });
Или просто добавьте новый метод расширения
public static IEnumerable<T> ConcatSingle<T>(this IEnumerable<T> enumerable, T value) {
return enumerable.Concat(new [] { value });
}
Ответ 4
Вы можете использовать Enumerable.Concat:
var allLayers = image.Layers.Concat(new[] {image.ParentLayer});
Ответ 5
Вы можете сделать что-то вроде:
image.Layers.Concat(new[] { image.ParentLayer });
который объединяет перечисление с одноэлементным массивом, содержащим предмет, который вы хотите добавить
Ответ 6
Я сделал для этого небольшую функцию:
public static class CoreUtil
{
public static IEnumerable<T> AsEnumerable<T>(params T[] items)
{
return items;
}
}
Теперь это возможно:
image.Layers.Append(CoreUtil.AsEnumerable(image.ParentLayer, image.AnotherLayer))
Ответ 7
Я использую следующие методы расширения, чтобы избежать создания бесполезного Array
:
public static IEnumerable<T> ConcatSingle<T>(this IEnumerable<T> enumerable, T value) {
return enumerable.Concat(value.Yield());
}
public static IEnumerable<T> Yield<T>(this T item) {
yield return item;
}
Ответ 8
Если вам нравится синтаксис .With, напишите его как метод расширения. IEnumerable не заметит другого.
Ответ 9
Существует метод Concat, который объединяет две последовательности.
Ответ 10
/// <summary>Concatenates elements to a sequence.</summary>
/// <typeparam name="T">The type of the elements of the input sequences.</typeparam>
/// <param name="target">The sequence to concatenate.</param>
/// <param name="items">The items to concatenate to the sequence.</param>
public static IEnumerable<T> ConcatItems<T>(this IEnumerable<T> target, params T[] items)
{
if (items == null)
items = new [] { default(T) };
return target.Concat(items);
}
Это решение основано на ответе realbart. Я скорректировал его, чтобы разрешить использование одного значения null
в качестве параметра:
var newCollection = collection.ConcatItems(null)
Ответ 11
Append
и Prepend
теперь добавлены в среду .NET Standard, поэтому вам больше не нужно писать свои собственные. Просто сделайте следующее:
image.Layers.Append(image.ParentLayer)
См. Каковы 43 API, которые находятся в .Net Standard 2.0, но не в .Net Framework 4.6.1? для отличного списка новых функций.