压缩/合并两个排序列表

本文关键字:两个 排序 列表 合并 压缩 | 更新日期: 2023-09-27 18:30:40

我有两个排序词典,都带有类型签名

SortedDictionary<decimal, long> A
SortedDictionary<decimal, long> B

我想合并键相同的两个列表,从而创建一个新列表,例如

SortedDictionary<decimal, KeyValuePair<long,long>>
or
SortedDictionary<decimal, List<long>>

这可能不是处理这种情况的最佳方式,但有人可以告诉我如何做到这一点或更好的方法来处理它。

压缩/合并两个排序列表

这就是我得到的:

SortedDictionary<decimal, List<long>> merged = new SortedDictionary<decimal, List<long>>
 (
   A.Union(B)
   .ToLookup(x => x.Key, x => x.Value)
   .ToDictionary(x => x.Key, x => new List<long>(x))
 );

编辑:上述解决方案选择两个集合中未包含的键。这应该选择键相同的位置:

SortedDictionary<decimal, List<long>> merged = new SortedDictionary<decimal, List<long>>
 (
   A.Where(x=>B.ContainsKey(x.Key))
   .ToDictionary(x => x.Key, x => new List<long>(){x.Value, B[x.Key]})
 );

只需使用 LINQ 即可执行此操作:

var query = from a in A
            join b in B
                on a.Key equals b.Key
            select new {
                Key = a.Key,
                Value = Tuple.Create(a.Value, b.Value)
            };
var merged = new SortedDictionary<decimal, Tuple<long, long>>(
                 query.ToDictionary(x => x.Key, x => x.Value)
             );

我认为您应该使用Tuple<long, long>作为合并词典中的TValue

我认为另一种

LINQ 方法可以更好地捕捉集合操作方面的意图:

SortedDictionary<decimal, long> a = new SortedDictionary<decimal, long>();
SortedDictionary<decimal, long> b = new SortedDictionary<decimal, long>();
a.Add(0, 10);
a.Add(1, 10);
a.Add(2, 100);
a.Add(100, 1);
b.Add(0, 4);
b.Add(4, 4);
b.Add(2, 10);
var result = a.Union(b)
    .GroupBy(x => x.Key)
    .ToDictionary(x => x.Key, x => x.Select(y => (long)y.Value).ToList());

尝试这样的事情,这并不容易:

Dictionary<decimal, long> dic1 = new Dictionary<decimal, long>{ {3,23}, {2,3}, {5,4}, {6,8}};
    Dictionary<decimal, long> dic2 = new Dictionary<decimal, long>{ {3,2}, {2,5}, {5,14}, {12,2}};

    //recover shared keys (the keys that are present in both dictionaries)
    var sharedKeys = dic1.Select(dic => dic.Key).Intersect(dic2.Select(d2=>d2.Key));
    sharedKeys.Dump();
    //add to the fìnal dictionary
    var final = new Dictionary<decimal, List<long>>();
    foreach(var shk in  sharedKeys) {
       if(!final.ContainsKey(shk)) 
          final[shk] = new List<long>(); 
        final[shk].Add(dic1[shk]);
        final[shk].Add(dic2[shk]);
    }
**EDIT** 
//Skip below part if you need only keys present on both dictionaries.
///-----------------------------------------------------------------
    //get unique keys present in Dic1 and add
    var nonsharedkeys1 = dic1.Select(d=>d.Key).Where(k=>!sharedKeys.Contains(k)); 
    foreach(var nshk in  nonsharedkeys1) {
        final[nshk] = new List<long>();             
        final[nshk].Add(dic1[nshk]);        
    }
     //get unique keys present in Dic2 and add
    var nonsharedkeys2 =  dic2.Select(d=>d.Key).Where(k=>!sharedKeys.Contains(k));
    foreach(var nshk in  nonsharedkeys2) {
        final[nshk] = new List<long>();             
        final[nshk].Add(dic2[nshk]);        
    }

应该为你工作。

你可以像这样"滥用"ConcatAggregate

var A = new SortedDictionary<decimal,long>();
var B = new SortedDictionary<decimal,long>();
A.Add(1, 11);
A.Add(2, 22);
A.Add(3, 33);
B.Add(2, 222);
B.Add(3, 333);
B.Add(4, 444);
var C = A.Concat(B).Aggregate(
    new SortedDictionary<decimal, List<long>>(),
    (result, pair) => {
        List<long> val;
        if (result.TryGetValue(pair.Key, out val))
            val.Add(pair.Value);
        else
            result.Add(pair.Key, new[] { pair.Value }.ToList());
        return result;
    }
);
foreach (var x in C)
    Console.WriteLine(
        string.Format(
            "{0}:'t{1}",
            x.Key,
            string.Join(", ", x.Value)
        )
    );

生成的输出:

1:      11
2:      22, 222
3:      33, 333
4:      444

这几乎与您编写了一个"普通"foreach并且实际上可以在任何IEnumerable<KeyValuePair<decimal, long>>(不仅仅是SortedDictionary<decimal, long>)上工作,并且如果需要,可以轻松扩展到两个以上的输入集合。

不幸的是,它也完全忽略了输入SortedDictionary是排序的,因此性能不是最佳的。为了获得最佳性能,您必须摆弄每个输入排序词典的线性前进单独IEnumerator,同时不断比较底层元素 - 您可以完全避免TryGetValue这样......