Überprüfen Sie, ob KeyValuePair mit FirstOrDefault von LINQ vorhanden ist


75

Ich habe ein Wörterbuch vom Typ

Dictionary<Guid,int>

Ich möchte die erste Instanz zurückgeben, in der eine Bedingung erfüllt ist

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

Wie überprüfe ich jedoch, ob ich tatsächlich ein KeyValuePair zurückerhalte? Ich kann anscheinend nicht! = Oder == verwenden, um ohne einen Compilerfehler gegen die Standardeinstellung (KeyValuePair) zu prüfen. Es gibt einen ähnlichen Thread hier , die nicht ganz scheint eine Lösung zu haben. Ich bin tatsächlich in der Lage, mein spezielles Problem zu lösen, indem ich den Schlüssel erhalte und die Standardeinstellung von Guid überprüfe, aber ich bin gespannt, ob es eine gute Möglichkeit gibt, dies mit dem Schlüsselwertpaar zu tun. Vielen Dank


Ich fand diese Antwort auf eine andere Frage hilfreich. Verwenden Sie im Grunde genommen das Ergebnis .Where()und verwenden Sie es dann .Any(), um zu entscheiden, ob Sie ein Ergebnis zurückbekommen haben oder nicht.
Jeff B

Antworten:


107

Wenn Sie sich nur um die Existenz kümmern, könnten Sie ContainsValue(0)oder Any(p => p.Value == 0)stattdessen verwenden? Die Suche nach Wert ist ungewöhnlich für a Dictionary<,>; Wenn Sie nach Schlüssel suchen, können Sie verwenden TryGetValue.

Ein anderer Ansatz:

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

Dies gibt eine Klasse zurück - so wird es sein, nullwenn es nicht gefunden wird.


6
Das ist ein guter Trick, bei dem anonyme Typen als Strukturen maskiert werden. Daran muss ich mich erinnern.
Andre Luus

1
Nein, das habe ich nicht gemeint. Tupel sind einfacher, daher ist es nicht wirklich sinnvoll zu glauben, dass anonyme Typen "versuchen, wie Tupel auszusehen". Die Idee hinter meinem Kommentar war, dass Sie bei Verwendung vareine Struktur durch einen anonymen Typ ohne Referenzkorrekturen ersetzen können, wie Sie es oben getan haben.
Andre Luus

1
Der anonyme Klassenansatz ist hilfreich, insbesondere wenn Sie mit dem resultierenden Wert etwas tun möchten, wenn er gefunden wird. Spart mir die Mühe, das Prädikat zweimal eingeben zu müssen (einmal, um nach .Any zu suchen, zweitens, um .First zu greifen). Das ist perfekt und genau das, was ich für ein ähnliches Problem brauchte.
Mike Loux

1
Beachten Sie, dass Sie die anonymen Typ-Eigenschaftsnamen weglassen können, als würden sie die zugewiesenen Eigenschaftsnamen automatisch verwenden (die in diesem Fall identisch sind)p => new { p.Key, p.Value }
oatsoda

26

Ich schlage vor, Sie ändern es auf folgende Weise:

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

Sie können dann sehen, ob die Liste leer ist oder nicht, und den ersten Wert annehmen, wenn dies nicht der Fall ist, z

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

Beachten Sie, dass es kein wirkliches Konzept für einen "ersten" Eintrag in einem Wörterbuch gibt - die Reihenfolge, in der er iteriert wird, ist nicht genau definiert. Wenn Sie das Schlüssel / Wert-Paar erhalten möchten, das zuerst mit diesem Wert eingegeben wurde, benötigen Sie ein auftragserhaltendes Wörterbuch.

(Dies setzt voraus, dass Sie den Schlüssel tatsächlich wissen möchten. Wenn Sie sich gerade nach einer Existenzprüfung befinden, ist Marc's Lösung am besten geeignet.)


19

Verwenden Sie das Schlüsselwort default ().

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

1
Ich denke, das Ergebnis sollte invertiert werden, da: bool existiert =! Available.Equals (Standard (KeyValuePair <Guid, int>));
Jaime

9

Was Sie wollen, ist eine AnyMethode, die Ihnen auch das passende Element gibt. Sie können diese Methode einfach selbst schreiben.

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

Ich denke, ich würde dies wahrscheinlich TryGetFirst oder TryFirst nennen, da es TryGetValue / TryParse ähnelt.
Jon Skeet

TryGetFirst ist ziemlich gut. Aber letztendlich können Sie es benennen, was Sie wollen.
Samuel

(Aber schöne Idee für eine Erweiterungsmethode - +1 :)
Jon Skeet

2

Sie könnten überprüfen, ob

available.Key==Guid.Empty

-1

Eine Möglichkeit, den Standardwert einer Struktur wie KeyValuePair zu überprüfen, ohne den Typ anzugeben, besteht darin, mit Activator eine neue Instanz zu erstellen:

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

Ich denke, dies ähnelt wahrscheinlich Florians Antwort mit dem Schlüsselwort default (). Ihr Ansatz ist zur Laufzeit möglicherweise langsamer.
jm.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.