2011-02-03 28 views
39

Về cơ bản tôi đang cố gắng để làm một cái gì đó như thế này:Có phương pháp Linq nào để thêm một mục đơn lẻ vào một tài khoản số <T> không?

image.Layers 

mà trả về một IEnumerable cho tất cả các lớp trừ lớp Parent, nhưng trong một số trường hợp, tôi chỉ muốn làm:

image.Layers.With(image.ParentLayer); 

vì nó chỉ được sử dụng ở một vài nơi so với 100s của việc sử dụng thông thường được thỏa mãn bởi image.Layers. Đó là lý do tại sao tôi không muốn tạo một tài sản khác cũng trả về lớp Parent.

+0

https://github.com/morelinq/MoreLINQ#concat hỗ trợ điều này. https://www.nuget.org/packages/morelinq/ – mjwills

Trả lời

41

Một cách sẽ được để tạo ra một singleton-chuỗi ra của sản phẩm (ví dụ như một mảng), và sau đó Concat nó lên bản gốc:

image.Layers.Concat(new[] { image.ParentLayer }) 

Nếu bạn đang làm điều này thực sự thường xuyên, xem xét viết một phần mở rộng-method Append (hoặc tương tự), chẳng hạn như một listed here, mà sẽ cho phép bạn làm:

image.Layers.Append(image.ParentLayer) 
+1

Đề xuất kết nối MSFT tại đây: http://bit.ly/lpcWjU –

+0

@IanMercer Đề xuất đã hết hạn. – McKay

7

Bạn có thể sử dụng Enumerable.Concat:

var allLayers = image.Layers.Concat(new[] {image.ParentLayer}); 
1

Có phương pháp Concat mà tham gia hai chuỗi.

+3

Yếu tố thứ hai không phải là một chuỗi ... đó là điểm của câu hỏi. – nicodemus13

5

bạn có thể làm một cái gì đó như:

image.Layers.Concat(new[] { image.ParentLayer }); 

phù hợp với enum với một mảng phần tử đơn chứa nội dung bạn muốn thêm

2

Nếu bạn thích cú pháp của .Với, hãy viết nó làm phương pháp mở rộng. IEnumerable sẽ không nhận thấy một số khác.

11

Không có phương pháp đơn nào thực hiện việc này. Cách gần nhất là phương pháp Enumerable.Concat nhưng cố gắng kết hợp một số IEnumerable<T> với IEnumerable<T> khác. Bạn có thể sử dụng sau đây để làm cho nó làm việc với một yếu tố duy nhất

image.Layers.Concat(new [] { image.ParentLayer }); 

Hoặc chỉ cần thêm một phương pháp khuyến nông mới

public static IEnumerable<T> ConcatSingle<T>(this IEnumerable<T> enumerable, T value) { 
    return enumerable.Concat(new [] { value }); 
} 
3

Tôi đã từng làm một hàm chút thoải mái cho việc này:

public static class CoreUtil 
{  
    public static IEnumerable<T> AsEnumerable<T>(params T[] items) 
    { 
     return items; 
    } 
} 

Hiện tại, điều này có thể:

image.Layers.Append(CoreUtil.AsEnumerable(image.ParentLayer, image.AnotherLayer)) 
+1

'AsEnumerable' hiện là [một phương pháp mở rộng được xây dựng sẵn] (http://msdn.microsoft.com/en-us/library/vstudio/bb335435%28v=vs.100%29.aspx) kể từ .Net 3.5 , do đó, một tên khác có thể theo thứ tự. Ngoài ra, 'AsX' ngụ ý nó là một phương pháp mở rộng (không phải là phương pháp được cho là một động từ?), Vì vậy tôi không nghĩ đó là một cái tên tốt ở nơi đầu tiên. Tôi sẽ đề nghị 'Enumerate'. – ErikE

+0

Ha! Từ lâu. Vâng, tôi đã đi đến cùng một kết luận trong thời gian đó. Tôi vẫn sử dụng điều nhỏ nhặt, nhưng bây giờ nó là 'ToEnumerable'. 'Enumerate' cũng không tệ. –

+0

Tôi vẫn thấy 'ToEnumerable' như đề xuất một phương pháp mở rộng. Làm thế nào về 'CreateEnumerable'? :) – ErikE

24

Nhiều triển khai đã được đưa ra. Mỏ trông hơi khác một chút (nhưng cũng chỉ hoạt động)

Ngoài ra, tôi thấy nó thực tế cũng có quyền kiểm soát đối với ORDER. do đó, thông thường, tôi cũng có một phương thức ConcatTo, đặt phần tử mới op phía trước.

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; 
    } 
} 

Hoặc cách khác, sử dụng mảng được tạo ngầm.(Sử dụng params từ khóa) để bạn có thể gọi phương thức để thêm một hoặc nhiều mục tại một thời điểm:

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))); 
+0

Thông thường tôi không thích nhìn thấy các bài đăng cũ va vào trang chủ của tôi như thế này, nhưng tôi thực sự rất thích giải pháp của bạn :) – Rawling

+2

+1 để cung cấp câu trả lời không cần phân bổ danh sách mới để concat một phần tử duy nhất. Và cung cấp sự linh hoạt hơn ở đó! – KChaloux

+1

.NET có thể sẽ biên dịch tuyên bố lợi nhuận cho một đối tượng ẩn danh, được khởi tạo. –

3

tôi sử dụng phương pháp mở rộng sau đây để tránh tạo ra một vô dụng 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; 
} 
+0

+1 Triển khai tốt, nhưng tại sao lại tránh mảng? Tôi biết nó cảm thấy sai lầm khi tạo mảng, nhưng nó thực sự kém hiệu quả hơn tất cả các công việc ẩn mà C# làm cho các trình vòng lặp này? – dss539

+1

Câu hỏi hay, tôi chưa chấm điểm nó ... –

+1

Lợi nhuận sẽ phân bổ và trả về một số vô danh IE2umergiữ một tham chiếu đến mục của bạn, vì vậy điều này có thể mất nhiều bộ nhớ và thời gian hơn mảng đơn. –

0
/// <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); 
} 

Giải pháp này dựa trên realbart's answer. Tôi điều chỉnh nó để cho phép việc sử dụng một giá trị duy nhất null như một tham số:

var newCollection = collection.ConcatItems(null) 
Các vấn đề liên quan