2013-07-09 1 views
4

У меня есть большой список <> пары Name/Value и вам нужно найти, существует ли конкретное имя в этом списке ... если это обновление Значение, если NOT затем создайте новую пару Name/Value и добавьте ее в свой список.Обновить свойство или создать новый элемент, если он не существует. Lambda C#

Что такое синтаксис лямбда для этого?

Я попытался с помощью .где .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 (новый 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

Это не настоящая коллекция папок Name/Value, у нас есть дополнительные свойства в коллекции, поэтому, к сожалению, я не могу использовать словарьный подход ... но спасибо за вход =) – afreeland

+1

Ваш GetOrAdd Extension прекрасно работает =) – 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]; 
     } 
    } 
} 

Конструктор принимает выражение лямбда для загрузки данных. Вы можете использовать его как это:

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

Но рассмотреть возможность использования словаря, как это было предложено @ Сэм.

+0

Если вы собираетесь сделать из него метод расширения, тогда вы должны обобщить его. Если вы не собираетесь обобщать его, маловероятно, что это должен быть метод расширения. – Servy

+0

@Servy вы когда-либо создавали методы расширения для сопоставления между моделями и dto или viewmodels? Эти расширения были родовыми? Также нет никакой пользы от общего, если вы собираетесь искать по названию элемента и устанавливать его значение. Ограничения? :) –

+0

Я не говорю * все * методы расширения должны быть общими. Я говорю об этом конкретном методе. Если это то, что, по вашему мнению, вы собираетесь сделать много, до такой степени, что вы хотите, чтобы это был метод расширения, тогда он, вероятно, должен стать универсальным, поскольку это не займет много времени. Если он не обобщен, я не вижу, чтобы этот конкретный метод использовался достаточно часто, чтобы потребовать от него расширения. – Servy

0

DefaultIfEmpty не добавляет к спискам. Он возвращает указанное значение, если переданная ему коллекция пуста. Так что в вашем случае ничего не произойдет, потому что вы не назначаете результат чему-либо; просто позволяя ему отбрасываться.

Существует не простая цепь лямбда, чтобы делать то, что вы хотите. Вам нужно сделать два шага. Во-первых, вы можете увидеть, есть ли какие-либо результаты, которые соответствуют тому, что вы ищете, а затем добавьте, если нет.

Редактировать: в ответ на комментарий я пропустил обновление оригинала. Вы могли бы сделать что-то вроде этого:

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

Смежные вопросы