【问题标题】:Update property or create new element if it does not exist Lambda c#更新属性或创建新元素,如果它不存在 Lambda c#
【发布时间】:2013-07-09 15:27:34
【问题描述】:

我有一个很大的名称/值对列表,并且需要能够找到此列表中是否存在特定名称...如果存在则更新该值,如果不存在则创建一个新的名称/值对和将其附加到我的列表中。

执行此操作的 Lambda 语法是什么?

我尝试使用 .Where .DefaultIfEmpty 但它只返回一个空对象,但不会将其附加到我原来的“myList”

myList.Where(x => x.Name == 'some name').DefaultIfEmpty(new myobj(){ Name = 'some name').First().Value = 'some value';

我必须做这四个多个名称,所以如果我有一个简单的语法会使它很棒 =)

【问题讨论】:

  • 我猜您在代码中缺少 myList.Add() - myList.Where(x => x.Name == 'some name').DefaultIfEmpty(() => { myList.Add(new myobj(){ Name = 'some name').First().Value = 'some value'})};);

标签: c# .net lambda


【解决方案1】:

你可以使用这个扩展方法:

public static void UpdateOrAdd(this List<myobj> source, 
     string name, object value)
{
    var obj = source.FirstOrDefault(x => x.Name == name);
    if (obj == null)
    {
        obj = new myobj { Name = name };
        source.Add(obj);
    }

    obj.Value = value;
}

用法:

myList.UpdateOrAdd("some name", "some value");

但是考虑使用字典,正如@Sam 建议的那样。

【讨论】:

  • 如果你打算用它做一个扩展方法,那么你应该泛化它。如果您不打算对其进行泛化,那么它不太可能是扩展方法。
  • @Servy 你有没有为模型和 dto 或视图模型之间的映射创建扩展方法?那些扩展是通用的?如果您要按项目名称搜索并设置其值,那么通用也没有任何好处。约束? :)
  • 我并不是说 all 扩展方法应该是通用的。我说的是一种特殊的方法。如果你认为你会做很多事情,以至于你希望它成为一个扩展方法,那么它可能应该是通用的,因为它不需要做那么多。如果它没有被普遍化,那么我认为这种特定方法的使用频率不足以保证对其进行扩展。
  • 我喜欢这种方法...我也在考虑让它更通用。我们有几种类型的集合,我们可以从这种灵活的扩展方法中受益 =) .. 我喜欢这种方法,@lazyberezovsky ...关于将其重构为更通用的任何想法
  • @afreeland 如果您想要通用的东西,那么您将处理对通用参数或键和值选择器 (lambdas) 的约束,这将使您的代码难以理解。我认为这里最好的解决方案是使用Dictionary&lt;TKey,TValue&gt; 来存储键/值对。
【解决方案2】:

您的实际查询只是获取满足条件的第一个项目。 LINQ 用于 查询 而不是修改集合,因此您不应该将项目作为查询的一部分添加到集合中;将其作为处理查询的一部分。

var match = list.FirstOrDefault(x => x.Name == "some name");
if(match != null)
    match.Value = "something else";
else
    list.Add(new MyObject(){...});

如果您想要更通用的 GetOrAdd 方法,您也可以创建一个:

public static T GetOrAdd<T>(this IList<T> list, Func<T, bool> predicate,
    Func<T> constructor)
{
    var match = list.FirstOrDefault(predicate);
    if(match == null)
    {
        match = constructor();
        list.Add(match);
    }

    return match;
}

使用它,您可以编写如下内容:

var item = list.GetOrAdd(obj => obj.Name == "Some Name", () => new MyObj(){...});
item.Value = "Some Value";

这样做后,请强烈考虑对这个集合使用 Dictionary,而不是成对的 List,因为它可以根据键更有效地搜索。

如果您确实有 Dictionary,那么执行此操作的代码将非常简单:

dictionary["some name"] = "some value";

除了代码更短之外,它还将显着更快地执行。

【讨论】:

  • 这不是真正的名称/值对集合,我们在集合上有其他属性,所以很遗憾我无法使用字典方法...但感谢您的输入 =)
【解决方案3】:

碰巧我刚刚为我自己的项目编写了这个类,使用Dictionary

public class CachedLoader<K, T> : Dictionary<K, T>
{
    private Func<K,T> GetItem = null;
    public CachedLoader(Func<K,T> getItem)
    {
        this.GetItem = getItem;
    }

    public new T this[K key]
    {
        get
        {
            if (!base.ContainsKey(key)) base[key] = GetItem(key);
            return base[key];
        }
    }
}

构造函数采用 lambda 表达式来加载数据。你可以这样使用它:

CachedLoader<Guid, Employee> MOEmployees 
     = new CachedLoader<Guid, Employee>(id => EmployeeManager.List(id));

你会这样消费它:

Guid employeeId = ...;
MOEmployees[employeeId]

没有必要从您正在使用数据的代码中显式创建/加载项目,因为该类会为您处理它 - 您只需在构造函数中指定如何执行它。您可以调整构造函数以创建您需要的值。

如果您卡在List 上,那么您也可以轻松地将其调整为该结构。

【讨论】:

    【解决方案4】:

    DefaultIfEmpty 不追加到列表。如果传递给它的集合为空,则返回指定的值。因此,在您的情况下,什么都不会发生,因为您没有将结果分配给任何东西;只是允许它被丢弃。

    没有一个简单的 lambda 链可以做你想做的事。你必须做两个步骤。首先,您可以查看是否有任何结果与您要查找的内容相匹配,如果没有,则追加。

    var defaultObj = new myobj() { Name = "default name", Value = "default value"};
    if(!list.Any(x => x.Name == "some name")){
      list.Add(defaultObj);
    }
    

    编辑:作为对评论的回应,我确实错过了更新原件。你可以这样做:

    var obj = list.FirstOrDefault(x => x.Name == "some name");
    if(obj == null){
        obj = new myobj() { Name = "default name" };
        list.Add(obj);
    } 
    obj.Value = "some value";
    

    【讨论】:

    • 如果它已经存在,这不会更改具有给定名称的项目。
    • 添加一个 else 语句。
    • 那么您将在列表中进行两次线性搜索,而不是一次。
    【解决方案5】:

    使用Any()

    if(list.Any(x => x.Name == "some name"))
    {
        // Replace
    }
    else
    {
        // Add
    }
    

    【讨论】:

    • 这是在集合中进行两次线性搜索以找到它,一次用于Any,再次在if 中进行编辑。
    猜你喜欢
    • 1970-01-01
    • 2017-05-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-16
    • 2021-02-28
    • 2018-04-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多