微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

从缺少C#键的列表中创建完整集

如何解决从缺少C#键的列表中创建完整集

我已经进行了很多挖掘工作,但是我似乎找不到针对这个特定问题的答案;可以解决类似的问题,但是没有什么比这个更合适的。

本质上,我想做的是在列表中添加具有认值的缺失键。我有一个具有以下结构的List >():

键:值

name : Orange
actualname : Orango
name : Lime
fullname : Lime Lime
actualname : Limo

从上面的列表中,我想创建一个缺少键集中的完整集。

期望键:值

name : Orange
fullname : ""
actualname : Orango
name : Lime
fullname : Lime Lime
actualname : Limo

我正在尝试以下代码

var list = new List<keyvaluePair<string,string>>
{
        new keyvaluePair<string,string>("name","Orange"),new keyvaluePair<string,string>("actualname","Orango"),"Lime"),string>("fullname","Lime Lime"),"Limo")
};
var distinctKeys = list
    .Select(pair => pair.Key)
    .distinct()
    .OrderBy(pair => pair)
    .ToArray();
var lastKeyIndex = -1;

for (var index = 0; index < list.Count; index++)
{
    var currentKeyIndex = lastKeyIndex + 1 == distinctKeys.Length ? 0 : lastKeyIndex + 1;
    var currentKey = distinctKeys[currentKeyIndex];

    if (list[index].Key != currentKey)
    {
        list.Insert(index,string>(currentKey,string.Empty));
    }

    lastKeyIndex = currentKeyIndex;
}

for (var index = lastKeyIndex+1; index < distinctKeys.Length; index++)
{
    list.Add(new keyvaluePair<string,string>(distinctKeys[index],string.Empty));
}

但是它没有给我期望的输出

另一种尝试:

键:值

contacts.coid : 2003984
createdon : 2020-09-10
c_id : fcd5937d
contacts.coid : 2024489
createdon : 2020-09-10
contacts.fullname : Mark
contacts.coid : 99
c_id : 7e70096e
contacts.coid : 2024496
createdon : 2020-09-10
contacts.fullname : Simon
c_id : ebbbd1f4

预期产量

期望键:值

contacts.coid : 2003984
createdon : 2020-09-10
contacts.fullname : ""
c_id : fcd5937d
contacts.coid : 2024489 
createdon : 2020-09-10
contacts.fullname : Mark
c_id : ""
contacts.coid : 99
createdon : ""
contacts.fullname : ""
c_id : 7e70096e
contacts.coid : 2024496
createdon : 2020-09-10
contacts.fullname : Simon
c_id : ebbbd1f4

任何想法都可以解决这个问题。

解决方法

给出每个分组的第一个键,您可以对其进行分组,您可以创建一个完整的键列表,该键列表按每组的部分顺序排序,然后展开每个组以具有完整的键集。

首先,对IEnumerable进行一些扩展,使您可以对谓词进行分组(在true时开始每个组),对DistinctBy进行扩展:

public static class IEnumerableExt {
    // TRes seedFn(T FirstValue)
    // TRes combineFn(TRes PrevResult,T CurValue)
    // Based on APL scan operator
    // Returns TRes
    public static IEnumerable<TRes> Scan<T,TRes>(this IEnumerable<T> items,Func<T,TRes> seedFn,Func<TRes,T,TRes> combineFn) {
        using (var itemsEnum = items.GetEnumerator()) {
            if (itemsEnum.MoveNext()) {
                var prev = seedFn(itemsEnum.Current);

                while (itemsEnum.MoveNext()) {
                    yield return prev;
                    prev = combineFn(prev,itemsEnum.Current);
                }
                yield return prev;
            }
        }
    }

    // returns groups of T items each starting when testFn is true
    public static IEnumerable<IEnumerable<T>> GroupByUntil<T>(this IEnumerable<T> items,bool> testFn) =>
        items.Scan(item => (groupNum: 0,theItem: item),(a,item) => testFn(item) ? (a.Item1+1,item) : (a.Item1,item))
             .GroupBy(t => t.groupNum)
             .Select(tg => tg.Select(t => t.theItem));

    // returns a single item from each group of items by keyFn(item) picked by pickFn(itemGroup)
    public static IEnumerable<T> DistinctBy<T,TKey>(this IEnumerable<T> items,TKey> keyFn,Func<IGrouping<TKey,T>,T> pickFn,IEqualityComparer<TKey> comparer = null) =>
        items.GroupBy(keyFn,comparer).Select(pickFn);
}

给出每个组的第一个键:

var firstKey = "name";

您现在可以根据按键在每个集合中出现的位置来对其进行部分排序,然后对不同按键进行排序:

var ordering = list.GroupByUntil(kvp => kvp.Key == firstKey)
                   .OrderBy(g => g.Count())
                   .SelectMany((g,sn) => g.Select((g,n) => new { g.Key,n = (sn+1)*n }))
                   .OrderBy(kn => kn.n)
                   .DistinctBy(kn => kn.Key,g => g.Last())
                   .ToDictionary(kn => kn.Key,kn => kn.n);
var keySet = list.Select(kvp => kvp.Key).Distinct().OrderBy(k => ordering[k]).ToList();

使用keySet,您可以扩展每组项目以具有所有键:

var ans = list.GroupByUntil(kvp => kvp.Key == firstKey)
              .Select(g => g.ToDictionary(l => l.Key,l => l.Value))
              .SelectMany(d => keySet.Select(k => new KeyValuePair<string,string>(k,d.TryGetValue(k,out var v) ? v : "")));

如果您希望仍将最终集合分组,只需将SelectMany替换为Select

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。