web-dev-qa-db-ja.com

LINQ:与えられた値のリストのキーをディクショナリから取得する、またはその逆

コード_Dictionary<TKeys, TValues> data;_に次の構造があります。両方のデータ型でいくつかのLINQクエリを実行しており、KeysValuesを切り替える必要があることがよくあります。特定の値のキーのリストを取得する最良の方法は何ですか?以前のLINQクエリの結果として、通常は「IEnumerable」と「IEnumerable」があり、IEnumerable<TKeys> Dictionary.GetAllKeys(IEnumerable<IValues> vals)IEnumerable<TValues> Dictionary.GetAllValues(IEnumerable<IKeys> keys)のようにしたいことに注意してください。

多分私はこのタスクのために他のデータコンテナが必要ですか?

よろしく、アレクサンダー。

18
 var values = dictionary.Where(x => someKeys.Contains(x.Key)).Select(x => x.Value);
 var keys = dictionary.Where(x => someValues.Contains(x.Value)).Select(x => x.Key);
31
Bala R

A Dictionary<,>は、値によってキーを検索するのに本当に適していません。 この回答で行った のように双方向の辞書を書くことはできますが、必ずしも必要ではありませんが最善のアプローチではありません。

もちろん、あなたはcanをキー/値ペアのシーケンスとして辞書を使用することができるので、次のようにすることができます:

var keysForValues = dictionary.Where(pair => values.Contains(pair.Value))
                              .Select(pair => pair.Key);

これはO(n)演算)になることに注意してください。「値」がHashSetまたは同様のもの(効率的な包含チェック付き)であってもです。

編集:あなたが本当に必要としない場合、キー/値の関係が必要です-それが単なるペアのようなものである場合は、List<Tuple<Foo, Bar>>は、ある程度の意味があります。クエリは基本的に同じになります:

public IEnumerable<T1> GetAllFirst<T1, T2>(IEnumerable<Tuple<T1, T2>> source,
                                           IEnumerable<T2> seconds)
{
    HashSet<T2> secondsSet = new HashSet<T2>(seconds);
    return source.Where(pair => secondsSet.Contains(pair.Item2));
}

public IEnumerable<T2> GetAllSecond<T1, T2>(IEnumerable<Tuple<T1, T2>> source,
                                            IEnumerable<T1> firsts)
{
    HashSet<T1> firstsSet = new HashSet<T1>(firsts);
    return source.Where(pair => firstsSet.Contains(pair.Item1));
}
11
Jon Skeet

最良の方法は、キーと値のペアのコレクションに対してlinqクエリを実行し、選択プロジェクションを使用して、クエリの最後でキーまたは値を選択することです。この方法では、クエリの最後にルックアップを実行する必要はありません。

例えば:

  Dictionary<string, string> data = new Dictionary<string, string>();
  // select all values for keys that contain the letter 'A'
  var values = data.Where(pair => pair.Key.Contains("A"))
                   .Select(pair => pair.Value);
1
ColinE