23

Dictionary<MyType, List<MyOtherType>>
に変換したいタイプの変数がありますLookup<MyType, MyOtehrType>

Lambda関数を使用して、最初に辞書をフラット化し、次にを使用してこれをルックアップに変換したいと思いましたToLookup()。私は辞書で行き詰まりました。SelectManyを使用することを考えましたが、機能しません。誰かがそれを行う方法を知っていますか?

4

5 に答える 5

26

Jonの方法と同じですが、匿名タイプの作成を避けます。

var lookup = dictionary
            .SelectMany(p => p.Value, Tuple.Create)
            .ToLookup(p => p.Item1.Key, p => p.Item2);
于 2014-11-25T13:16:27.903 に答える
18

どうですか:

var lookup = dictionary.SelectMany(pair => pair.Value,
                                   (pair, Value) => new { pair.Key, Value })
                       .ToLookup(pair => pair.Key, pair => pair.Value);

辞書にすでにすべての情報が適切にグループ化されている場合、これを行うのは少しもったいないように感じますが、それを回避する簡単な方法はわかりません。もちろんILookup<TKey, TValue>、辞書のラッパーを使って自分自身を実装することもできます...

于 2009-09-23T06:15:33.157 に答える
1

すでにいくつかの答えがここにありますが、これを参考のためにここに置いてください。これにより、値のリストを含む辞書が反転し、それらの値がルックアップリストのキーになります。

var myLookup = myDict.SelectMany(p => p.Value, 
        (pair, id) => Tuple.Create(id, pair.Key))
    .ToLookup(p => p.Item1, p => p.Item2);

注釈付き


var myLookup = myDict.SelectMany(
        // specify that the select many is to be based off the Value which is a list of items
        p => p.Value, 
        // Using the individual items from that list, create a tuple of that item and the dictionary key it was under
        (pair, id) => Tuple.Create(id, pair.Key))
        // use the item as the lookup key, and put the original dictionary key (that
        // had that value underneath them) in the list of lookup values.
    .ToLookup(p => p.Item1, p => p.Item2);
于 2020-01-08T15:31:30.113 に答える
0

質問に対する答えではありませんが、これは関連情報であり、ここに投稿する必要があると思います。

考慮すべきいくつかのエッジケースがあります。それらはすべて、キーはあるが価値がない辞書の項目に関するものです。

これは予想される動作です。さまざまな目的のために設計された辞書とルックアップ。

var dic = new Dictionary<bool, IEnumerable<bool?>> { [true] = null };
var lookup = dic.ToLookup();

Assert.AreEqual(1, dic.Count);
Assert.AreEqual(0, lookup.Count);

Assert.IsTrue(dic.ContainsKey(true));
Assert.IsFalse(lookup.Contains(true));

Assert.IsFalse(dic.ContainsKey(false));
Assert.IsFalse(lookup.Contains(false));

dic[false] -> Exception
lookup[false] -> bool?[0]
于 2020-03-16T03:26:02.567 に答える
0

パーティーに遅れましたが、すべてを再度列挙して一時的なタプル/匿名タイプを作成する必要なしに、これは機能するはずだと思います。

public static ILookup<TKey, TElement> ToLookup<TKey, TElement>(
    this IEnumerable<TKey> keys,
    Func<TKey, IEnumerable<TElement>> selector)
{
    return new ManualLookup<TKey, TElement>(keys, selector);
}

private class ManualLookup<TKey, TElement> : ILookup<TKey, TElement>
{
    private IEnumerable<TKey> _keys;
    private Func<TKey, IEnumerable<TElement>> _selector;

    public ManualLookup(IEnumerable<TKey> keys, Func<TKey, IEnumerable<TElement>> selector)
    {
        _keys = keys;
        _selector = selector;
    }

    public IEnumerable<TElement> this[TKey key] => _selector(key);

    public int Count => _keys.Count();

    public bool Contains(TKey key) => _keys.Contains(key);

    public IEnumerator<IGrouping<TKey, TElement>> GetEnumerator() => _keys
        .Select(key => new ManualGrouping<TKey, TElement>(key, _selector(key)))
        .GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

private class ManualGrouping<TKey, TElement> : IGrouping<TKey, TElement>
{
    private TKey _key;
    private IEnumerable<TElement> _enumerable;

    public ManualGrouping(TKey key, IEnumerable<TElement> enumerable)
    {
        _key = key;
        _enumerable = enumerable;
    }

    public TKey Key => _key;

    public IEnumerator<TElement> GetEnumerator() => _enumerable.GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

次に、次のようなことを行うことができます。

Dictionary<MyType, List<MyOtherType>> dictionary;
return dictionary.Keys.ToLookup(key => 
{
    if (dictionary.TryGetValue(key, out var list)
    {
        return list;
    }

    return Enumerable.Empty<MyOtherType>();
});
于 2021-07-01T05:28:21.880 に答える