2013-07-09 74 views
4

我有一個名單/值對大列表<>需要能夠找到一個特定的名稱是否存在於此列表中...如果更新值,如果不是,則創建一個新的名稱/值對並將其附加到我的列表中。更新屬性或創建新的元素,如果它不存在Lambda c#

這是什麼Lambda語法?

我一直在使用。凡.DefaultIfEmpty嘗試,但它只是返回一個空的對象,但它不追加到我原來的「myList中」

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

我必須做的這四多個名字,所以如果我有一個簡單的語法,將使其極大=)

+5

使用字典? –

+0

我猜你缺少代碼中的myList.Add() - myList.Where(x => x.Name =='some name')。DefaultIfEmpty((=)=> {myList.Add(new myobj( ){Name ='some name')。First()。Value ='some value'})};); – Jegan

回答

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

而且除了是在更短的代碼,它會執行大幅更快。

+0

它不是一個真正的名稱/值對集合,我們有集合上的附加屬性,所以不幸我無法使用字典方法......但是謝謝輸入=) – afreeland

+1

您的GetOrAdd擴展工作得很漂亮=) – afreeland

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,那麼你可以很容易地適應這種結構。

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建議。

+0

If你將會制定一個擴展方法,然後你應該通用化它。如果你不想泛化它,那麼它不可能是一個擴展方法。 – Servy

+0

@Servy是否曾創建過模型與dto或視圖模型之間映射的擴展方法?那些擴展是通用的?如果您要按項目名稱進行搜索並設置其值,則通用性也沒有好處。約束? :) –

+0

我不是說*所有*擴展方法應該是通用的。我正在說這個特殊的方法。如果你認爲你會做很多事情,那麼你希望它成爲一種擴展方法,那麼它應該是通用的,因爲它不需要做太多的事情。如果它沒有被廣義化,那麼我不會看到這個特定的方法被經常使用足以保證進行擴展。 – Servy

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

如果它已經存在,這不會改變具有給定名稱的項目。 – Servy

+0

在確定的else語句上使用。 –

+0

然後你通過列表​​進行兩個線性搜索,而不是一個。 – Servy

0

使用Any()

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

這是通過集合進行兩次線性搜索以找到它,一次用於「Any」,並再次在「if」中進行編輯。 – Servy

相關問題