4

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

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

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

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

我必须做这四个多个名称,所以如果我有一个简单的语法,那就太好了=)

4

5 回答 5

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

考虑使用 dictionary,正如@Sam 建议的那样。

于 2013-07-09T15:31:58.617 回答
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对这个集合使用 a 而不是 a Listof pair,因为它可以根据键更有效地搜索。

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

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

除了代码更短之外,它的执行速度也将大大加快。

于 2013-07-09T15:31:57.630 回答
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]

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

如果你被困在 a 上List,那么你也可以轻松地将其调整为该结构。

于 2013-07-09T15:30:14.387 回答
0

利用Any()

if(list.Any(x => x.Name == "some name"))
{
    // Replace
}
else
{
    // Add
}
于 2013-07-09T15:34:34.353 回答
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";
于 2013-07-09T15:33:41.733 回答