Есть ли метод 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)