C# 重复值的部分解组列表

C# 重复值的部分解组列表,c#,linq,C#,Linq,我知道如何使用LINQ对数据进行分组,我知道如何将其拆分为单独的项,但我不知道如何仅对其进行部分解组 我有一组数据如下所示: var data = new Dictionary<Header, Detail>() { { new Header(), new Detail { Parts = new List<string> { "Part1", "Part1", "Part2" } } } }; 对于更复杂的示例: var data = new Dictiona

我知道如何使用LINQ对数据进行分组,我知道如何将其拆分为单独的项,但我不知道如何仅对其进行部分解组

我有一组数据如下所示:

var data = new Dictionary<Header, Detail>()
{
    { new Header(), new Detail { Parts = new List<string> { "Part1", "Part1", "Part2" } } }
};
对于更复杂的示例:

var data = new Dictionary<Header, Detail>()
{
    { new Header(1), new Detail { Parts = new List<string> { "Part1", "Part1", "Part2" } } },

    { new Header(2), new Detail { Parts = new List<string> { "Part1", "Part2" } } },

    { new Header(3), new Detail { Parts = new List<string> { "Part1", "Part2", "Part2", "Part2", "Part3", "Part3"} } }
};

var desiredOutput = new List<KeyValuePair<Header, Detail>>()
{
    { new Header(1), new Detail { Parts = new List<string> { "Part1", "Part2" } } },
    { new Header(1), new Detail { Parts = new List<string> { "Part1" } } },

    { new Header(2), new Detail { Parts = new List<string> { "Part1", "Part2" } } },

    { new Header(3), new Detail { Parts = new List<string> { "Part1", "Part2", "Part 3" } } },
    { new Header(3), new Detail { Parts = new List<string> { "Part2", "Part3" } } },
    { new Header(3), new Detail { Parts = new List<string> { "Part2" } } }
};
var data=newdictionary()
{
{new Header(1),new Detail{Parts=new List{“Part1”,“Part1”,“Part2”}},
{new Header(2),new Detail{Parts=new List{“Part1”,“Part2”}},
{new Header(3),new Detail{Parts=new List{“Part1”、“Part2”、“Part2”、“Part3”、“Part3”}}
};
var desiredOutput=新列表()
{
{new Header(1),new Detail{Parts=new List{“Part1”,“Part2”}},
{new Header(1),new Detail{Parts=new List{“Part1”}},
{new Header(2),new Detail{Parts=new List{“Part1”,“Part2”}},
{new Header(3),new Detail{Parts=new List{“Part1”,“Part2”,“part3”}},
{new Header(3),new Detail{Parts=new List{“Part2”,“Part3”}},
{new Header(3),new Detail{Parts=new List{“Part2”}}
};

有什么建议吗

详细信息
部分中的元素创建一个
分类数据集
。转换为
列表的这是您的第一个组,
分类数据集
,实际上,
详细信息
中的每个元素只包含一个实例

将其从原始
详细信息
零件(或其副本)中删除。重复此操作,直到细节的大小为零

编辑:

尝试使用类似于单个Linq语句的内容。为了简单起见,让我使用列表

var total = new List<List<string>>() { 
    new List<string>(), 
    new List<string>(), 
    new List<string>(), 
    new List<string>(), 
    new List<string>(), 
    new List<string>() 
};

//the statement

var q = k.Aggregate(total, (listOlists, singleStrin) => {
    listOlists.Where(l => !l.Contains(singleStrin)).First().Add(singleStrin);
    return listOlists;
});
var total=new List(){
新列表(),
新列表(),
新列表(),
新列表(),
新列表(),
新名单()
};
//声明
var q=k.总(列表组、单一组分)=>{
其中(l=>!l.Contains(singleStrin)).First().Add(singleStrin);
回归列强;
});

基本上,我创建了一个累加器函数,仅当列表中还没有包含元素时,才将元素添加到字符串列表中。列表本身包含在累加器列表中。您需要初始化累加器列表,否则Linq语句将变得更加丑陋。

这将把一个字符串列表分解为多个没有重复项的字符串列表

List<string> oldParts = new List<string> { "Part1", "Part2", "Part2", "Part2", "Part3", "Part3" };
List<List<string>> allLists = new List<List<string>>();

foreach (string currentPart in oldParts)
{
    foreach (List<string> currentList in allLists)
    {
         // if currentList doesn't have the part, then 
         //    add part to the currentList, and process next part
         if (!currentList.Contains(currentPart))
         {
             currentList.Add(currentPart);
             goto NextPart;
         }
    }
    // if we get here, the part is already contained on in the lists
    // so add a new list to allLists
    // and add the part to the new list
    allLists.Add(new List<string> { currentPart });

    NextPart: ;
}     
List oldParts=新列表{“Part1”、“Part2”、“Part2”、“Part2”、“Part3”、“Part3”};
List ALLISTS=新列表();
foreach(oldParts中的字符串currentPart)
{
foreach(在所有列表中列出currentList)
{
//如果currentList没有该部件,则
//将零件添加到当前列表,然后处理下一个零件
如果(!currentList.Contains(currentPart))
{
currentList.Add(currentPart);
转到下一部分;
}
}
//如果我们到了这里,零件已经包含在列表中了
//因此,向AllList添加一个新列表
//并将该零件添加到新列表中
添加(新列表{currentPart});
下一部分:;
}     

不,实际上没有一个现有的LINQ函数可以完成所有这一切

本质上,如果您设想按每个字符串对
部分进行分组,并将每个组视为一行,那么您需要的是每个“列”。我使用了一个helper函数
GetNthValues
(该函数是为模拟LINQ风格的函数而设计的)。一旦你有了它,你就只需要对每个部分进行分组,调用函数,然后把结果放回字典里

public static Dictionary<Header, Detail> Ungroup(Dictionary<Header, Detail> input)
{
    var output = new Dictionary<Header, Detail>();

    foreach (var key in input.Keys)
    {
        var lookup = input[key].Parts.ToLookup(part => part);

        bool done = false;

        for (int i = 0; !done; i++)
        {
            var parts = lookup.GetNthValues(i).ToList();
            if (parts.Any())
            {
                output.Add(new Header(key.Value), new Detail { Parts = parts });
            }
            else
            {
                done = true;
            }
        }
    }

    return output;
}

public static IEnumerable<TElement> GetNthValues<TKey, TElement>(
    this ILookup<TKey, TElement> source, int n)
{
    foreach (var group in source)
    {
        if (group.Count() > n)
        {
            yield return group.ElementAt(n);
        }
    }
}
公共静态字典解组(字典输入)
{
var输出=新字典();
foreach(input.Keys中的var键)
{
var lookup=input[key].Parts.ToLookup(part=>part);
bool done=false;
对于(int i=0;!done;i++)
{
var parts=lookup.GetNthValues(i.ToList();
if(parts.Any())
{
Add(新标题(key.Value),新细节{Parts=Parts});
}
其他的
{
完成=正确;
}
}
}
返回输出;
}
公共静态IEnumerable GetNthValues(
此ILookup源,int n)
{
foreach(源中的var组)
{
if(group.Count()>n)
{
收益率-收益率组.ElementAt(n);
}
}
}

Linq在这方面帮不了你多少忙,但这里有一个扩展方法,它可以做到这一点:

public static IEnumerable<KeyValuePair<Header, Detail>> UngroupParts(
    this IEnumerable<KeyValuePair<Header, Detail>> data)
{
    foreach (var kvp in data)
    {
        Header header = kvp.Key;
        List<string> parts = kvp.Value.Parts.ToList();
        do
        {
            List<string> distinctParts = parts.Distinct().ToList();
            Detail detail = new Detail() { Parts = distinctParts };
            yield return new KeyValuePair<Header, Detail>(header, detail);

            foreach (var part in distinctParts)
                parts.Remove(part);
        }
        while (parts.Any());
    }
}

那么,您的输入仅仅是一个字符串列表,还是一个包含(可能有几个)键值对的字典呢?
{“Part1”、“Part2”、“Part3”}、{“Part2”}、{“Part2”}
,为什么没有
{“Part1”}、{“Part1”、“Part2”}
?这里有什么规定?@deerchao-我不知道你在问什么。在第二个示例的输入中,只有一个
Part1
,因此只有一个
Part1
获得输出。示例输入和所需输出为+1。@ThomSmith两个示例输入和两个示例输出偶数,一个简单案例和一个复杂案例。非常非常有用。有没有任何方法可以作为一个LINQ语句来实现这一点?或者我需要对整个输入集进行
foreach
,并构建一个新的变体吗?回答后,我知道您可能想要一个linq解决方案,我想是一个非常简单的解决方案!这并不完全是linq,因为我不知道如何在将元素添加到它的一个子列表后,让listOlists作为聚合器元素返回。我仍然认为这是一个很好的解决方案,完全与代码可读性作斗争:)@Gabber注意,这并不是一个特别有效的解决方案,因为如果数据集很大,它将无法扩展。还请注意,在这种情况下,您碰巧“知道”开始时需要的列表数量。您的代码缺少在列表不存在时添加列表的逻辑,实际上它需要这样做。您是对的,我知道此解决方案效率低下。我对这个答案的限制是Lambda表达式,它优先于时间复杂度。反对意见:您可以在
public static IEnumerable<KeyValuePair<Header, Detail>> UngroupParts(
    this IEnumerable<KeyValuePair<Header, Detail>> data)
{
    foreach (var kvp in data)
    {
        Header header = kvp.Key;
        List<string> parts = kvp.Value.Parts.ToList();
        do
        {
            List<string> distinctParts = parts.Distinct().ToList();
            Detail detail = new Detail() { Parts = distinctParts };
            yield return new KeyValuePair<Header, Detail>(header, detail);

            foreach (var part in distinctParts)
                parts.Remove(part);
        }
        while (parts.Any());
    }
}
var desiredOutput = data.UngroupParts();