簡體   English   中英

如何迭代集合並使用LINQ擴展方法更改值?

[英]How can I iterate over a collection and change values with LINQ extension methods?

假設我有一組消息,其中包含“UserID”(int)和“Unread”(bool)屬性。

對於UserID = 5的集合中的任何Message,如何使用LINQ擴展方法設置Unread = false?

所以,我知道我可以這樣做:

messages.Any(m => m.UserID == 5);

但是,如何使用擴展方法設置每個的Unread屬性呢?

注意:我知道我不應該在生產代碼中這樣做。 我只是想學習更多LINQ-fu。

實際上,這可以僅使用沒有ToList的內置LINQ擴展方法。
我相信這將與常規for循環非常相似。 (我還沒檢查過)

不敢在實際代碼中這樣做。

messages.Where(m => m.UserID == 5)
        .Aggregate(0, (m, r) => { m.Unread = false; return r + 1; });

作為額外的獎勵,這將返回其修改的用戶數量。

messages.Where(m => m.UserID == 5).ToList().ForEach(m => m.Unread = false);

然后提交更改。

標准LINQ擴展方法不包括針對方法的副作用。 但是,您可以自己實現它,也可以使用Reactive Extensions for .NET(Rx),如下所示:

messages.Where(m => m.UserID == 5).Run(m => m.Unread = false);

由於沒有明確的擴展方法可以執行ForEach ,因此您無論是使用輔助庫還是自己編寫foreach語句。

foreach (Message msg in messages.Where(m => m.UserID == 5))
{
    msg.Unread = false;
}

如果您確實想使用Linq語句來完成此操作,請使用ToList()方法創建集合的副本,訪問List類型的ForEach()方法:

messages.Where(m => m.UserID == 5).ToList().ForEach(m => m.Unread = false);

或將副作用放在Where()語句中:

messages.Where(m =>
{
    if (m.UserID == 5) { m.Unread = false; return true; }
    return false;
});

在任何一種情況下,我更喜歡使用顯式的foreach循環,因為它不會產生不必要的副本,並且比Where hack更清晰。

使用LINQ你不能,因為LINQ是一種查詢語言/擴展。 然而,有一個名為MoreLinq的項目,它定義了一個名為ForEach的擴展方法,它允許您傳遞將在每個元素上執行的操作。

所以,你可以使用MoreLinq:

messages.Where(m => m.UserID == 5).ForEach(m => m.Unread = false);

最好的祝福,
奧利弗哈納皮

這個答案是本着提供解決方案的精神 On可以創建一個擴展,它既可以執行謂詞( Where擴展),也可以執行這些項目所需的操作。

下面是一個名為OperateOn的擴展,它很容易編寫:

public static void OperateOn<TSource>(this List<TSource> items, 
                                      Func<TSource, bool> predicate, 
                                      Action<TSource> operation)
{
    if ((items != null) && (items.Any()))
    {
        items.All (itm =>
        {
            if (predicate(itm))
                operation(itm);

            return true;
        });

    }
}

這是它的實際應用:

var myList = new List<Item>
                   { new Item() { UserId = 5, Name = "Alpha" },
                     new Item() { UserId = 5, Name = "Beta", UnRead = true },
                     new Item() { UserId = 6, Name = "Gamma", UnRead = false }
                   };


myList.OperateOn(itm => itm.UserId == 5, itm => itm.UnRead = true);

Console.WriteLine (string.Join(" ",
                               myList.Select (itm => string.Format("({0} : {1})",
                                                                   itm.Name,
                                                                   itm.UnRead ))));

/* Outputs this to the screen

(Alpha : True) (Beta : True) (Gamma : False)

*/

...

public class Item
{
    public bool UnRead { get; set; }
    public int UserId { get; set; }
    public string Name { get; set; }
}

您應該能夠在Select()中執行此操作,記住lambda是函數的快捷方式,因此您可以根據需要放置盡可能多的邏輯,然后返回枚舉的當前項。 並且......為什么你不能在生產代碼中這樣做?

messages = messages
    .Select(m => 
    {
        if (m.UserId == 5) 
            m.Unread = true;
        return m;
    });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM