Перевірте, чи існує KeyValuePair за допомогою FirstOrDefault від LINQ


75

У мене є словник типу

Dictionary<Guid,int>

Я хочу повернути перший екземпляр, коли умова виконана, використовуючи

var available = m_AvailableDict.FirstOrDefault(p => p.Value == 0)

Однак, як мені перевірити, чи дійсно я повертаю KeyValuePair? Здається, я не можу використовувати! = Або == для перевірки за замовчуванням (KeyValuePair) без помилки компілятора. Існує нитки тут , не зовсім , здається, є рішення. Я насправді можу вирішити свою особливу проблему, отримавши ключ і перевіривши за замовчуванням Guid, але мені цікаво, чи є хороший спосіб зробити це за допомогою keyvaluepair. Дякую


Я знайшов цю відповідь на інше питання корисним. В основному використовуйте, .Where()а потім використовуйте .Any()результат, щоб вирішити, отримали ви результат назад чи ні.
Джефф Б,

Відповіді:


107

Якщо ви просто піклуєтесь про існування, можете використати ContainsValue(0)чи Any(p => p.Value == 0)замість цього? Пошук за значенням незвичний для a Dictionary<,>; якщо ви шукали за ключем, ви могли б використовувати TryGetValue.

Ще один підхід:

var record = data.Where(p => p.Value == 1)
     .Select(p => new { Key = p.Key, Value = p.Value })
     .FirstOrDefault();

Це повертає клас - так буде, nullякщо його не знайти.


6
Це акуратний фокус із використанням анонімних типів для маскування під структури. Мені доведеться це пам’ятати.
Андре Луус

1
Ні, це не те, що я мав на увазі. Кортежі простіші, тому насправді немає сенсу думати, що анонімні типи "намагаються виглядати як кортежі". Ідея мого коментаря полягала в тому, що якщо ви використовуєте var, ви можете замінити структуру анонімним типом без будь-яких виправлень посилань, як це було зроблено вище.
Andre Luus

1
Підхід до анонімного класу приємний, особливо якщо ви хочете зробити що-небудь із отриманим значенням, якщо його знайдете. Позбавляє мене проблеми з необхідністю вводити предикат двічі (один раз, щоб перевірити .Будь-який, другий - схопити. Перший). Це ідеально, і саме те, що мені потрібно для подібної проблеми.
Mike Loux

1
Зверніть увагу, що ви можете пропустити імена властивостей анонімного типу, так як якщо їх пропустити, вони автоматично використовуватимуть призначені імена властивостей (які в даному випадку однакові)p => new { p.Key, p.Value }
oatsoda

26

Я пропоную вам змінити це таким чином:

var query = m_AvailableDict.Where(p => p.Value == 0).Take(1).ToList();

Потім ви можете побачити, чи список порожній чи ні, і взяти перше значення, якщо ні, наприклад

if (query.Count == 0)
{
    // Take action accordingly
}
else
{
    Guid key = query[0].Key;
    // Use the key
}

Зауважте, що реального поняття "першого" запису у словнику немає - порядок його повторення не є чітко визначеним. Якщо ви хочете отримати пару ключ / значення, яка була вперше введена з цим значенням, вам знадобиться якийсь словник, що зберігає замовлення.

(Це передбачає, що ви насправді хочете знати ключ - якщо ви просто після перевірки існування, рішення Марка є найбільш підходящим.)


19

Використовуйте ключове слово за замовчуванням ().

bool exists = !available.Equals(default(KeyValuePair<Guid, int>));

1
Думаю, результат слід перевернути, оскільки: bool існує =! Available.Equals (за замовчуванням (KeyValuePair <Guid, int>));
Хайме

9

Те, що ви хочете, - це Anyметод, який також дає вам відповідний елемент. Ви можете легко написати цей метод самостійно.

public static class IEnumerableExtensions
{
  public static bool TryGetFirst<TSource>(this IEnumerable<TSource> source,
                                          Func<TSource, bool> predicate,
                                          out TSource first)
  {
    foreach (TSource item in source)
    {
      if (predicate(item))
      {
        first = item;
        return true;
      }
    }

    first = default(TSource);
    return false;
  }
}

Думаю, я б, мабуть, назвав це TryGetFirst або TryFirst, враховуючи схожість із TryGetValue / TryParse.
Джон Скіт,

TryGetFirst досить непоганий. Але зрештою ви можете назвати це як завгодно.
Самуель

(Але гарна ідея щодо методу розширення - +1 :)
Джон Скіт,


-1

Спосіб перевірки за значенням за замовчуванням для такої структури, як KeyValuePair, без зазначення типу - це створення нового екземпляра за допомогою Activator:

if (available.Equals(Activator.CreateInstance(available.GetType())))
{
    Console.WriteLine("Not Found!");
}

Я думаю, це, мабуть, схоже на відповідь Флоріана за допомогою ключового слова default (). Ваш підхід може бути повільнішим під час виконання.
jm.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.