2017-02-22 15 views
0
class Key { string s; int i; } 

LINQの集約辞書

私はこれが容易であるべきだと感じますが、私はそれを得ることができません。

おかげ

明確化:

var dict = new Dictionary<Key,int>(); 
dict.Add(new Key("a", 123), 19); 
dict.Add(new Key("a", 456), 12); 
dict.Add(new Key("a", 789), 13); 
dict.Add(new Key("b", 998), 99); 
dict.Add(new Key("b", 999), 11); 

と私は辞書を生成します:助け

"a" -> 12 
"b" -> 11 

希望。

+3

それはあなたがそれぞれの最小辞書値」によって何を意味するのか私にははっきりしていませんすべてのキーの上にキー "を押します。サンプル入力と期待される出力データを持つ[mcve]は、現在の形式の質問よりはるかに役立ちます。 –

+0

@JonSkeet質問が更新されました。 – CoderBrien

+0

これで、元の辞書のエントリをキーの 's'プロパティでグループ化し、次に、最も小さい辞書値を持つエントリだけに興味のある各グループにグループ化します。残りのすべての辞書エントリから、元のキーの 's'プロパティで、値が元の値である新しい辞書を作成しますか? – stakx

答えて

3

私はあなたがしようとしている正確に何を明確ないんだけど、あなたは例えば.Select(...および/または.ToDictionary(...

で別の辞書からのマッピングを行うことができます。

Dictionary<Key, int> original = ... 
Dictionary<string, int> mapped = original.ToDictionary((kvp) => kvp.Key.s, (kvp) => kvp.Key.i); 

あなたの質問がより明確になるように改善すれば、私は答えを改善します。

EDIT:あなたはキーsプロパティでグループ化したい

var d = dict.GroupBy(kvp => kvp.Key.s).ToDictionary(g => g.Key, g => g.Min(k => k.Value)); 

(質問が明らかになった)、その後、新しい辞書値として辞書値の最小値を選択します。

+0

@caesay質問が更新されました。 – CoderBrien

+0

@caesay各kvp.Key.sのminiumum kvp.Valueが必要です – CoderBrien

+0

@CoderBrien:そこに行きます! – caesay

1

.GroupByによって作成されたLookupをスキップするために、より汎用的な方法は:

public static Dictionary<K, V> aggregateBy<T, K, V>(
     this IEnumerable<T> source, 
     Func<T, K> keySelector, 
     Func<T, V> valueSelector, 
     Func<V, V, V> aggregate, 
     int capacity = 0, 
     IEqualityComparer<K> comparer = null) 
    { 
     var dict = new Dictionary<K, V>(capacity, comparer); 
     foreach (var t in source) 
     { 
      K key = keySelector(t); 
      V accumulator, value = valueSelector(t); 
      if (dict.TryGetValue(key, out accumulator)) 
       value = aggregate(accumulator, value); 
      dict[key] = value; 
     } 
     return dict; 
    } 

サンプル使用:

var dict = new Dictionary<Tuple<string,int>, int>(); 
    dict.Add(Tuple.Create("a", 123), 19); 
    dict.Add(Tuple.Create("a", 456), 12); 
    dict.Add(Tuple.Create("a", 789), 13); 
    dict.Add(Tuple.Create("b", 998), 99); 
    dict.Add(Tuple.Create("b", 999), 11); 

    var d = dict.aggregateBy(p => p.Key.Item1, p => p.Value, Math.Min); 

    Debug.Print(string.Join(", ", d));  // "[a, 12], [b, 11]" 
+0

私はこのケースでそれが必要だとは思わないが、非効率性を指摘してくれてありがとう! – CoderBrien