更新属性或创建新元素(如果它不存在)Lambda c#

时间:2013-07-09 15:27:34

标签: c# .net lambda

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

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

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

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

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

5 个答案:

答案 0 :(得分:5)

您可以使用此扩展方法:

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建议的那样。

答案 1 :(得分:3)

您的实际查询只是获取满足条件的第一个项目。 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";

除了缩短代码外,它还能更快地执行

答案 2 :(得分:1)

恰好我只是使用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,那么您也可以轻松地将其调整为该结构。

答案 3 :(得分:0)

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

答案 4 :(得分:0)

使用Any()

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