linq 如何根据所需的可变数量对多组值进行分组(C#)

p1iqtdky  于 2022-12-06  发布在  C#
关注(0)|答案(2)|浏览(113)

面对一个问题,我想我可能盯着太久了,我希望有人能给我指出正确的方向。我一直在尝试一些阵列操纵,我觉得我已经接近了一些方法,但还没有达到。
我想要的是:给定一个值数组(在本例中,我将使用简单的值'A', 'B', 'C', 'D'),以及每个值所需的最小出现次数),将这些值的集合分组为所需大小的能力。例如:

// when given this list of required amounts
var config = new[] {
    { Value: 'A', AmountRequired: 1 },
    { Value: 'B', AmountRequired: 2 },
    { Value: 'C', AmountRequired: 3 },
    { Value: 'D', AmountRequired: 4 }
};

// and this array of values (matches requirements exactly)
var values = new[] { 'A', 'B', 'B', 'C', 'C', 'C', 'D', 'D', 'D', 'D' };

// the logic would return
var results = [
    ['A'],
    ['B', 'B'],
    ['C', 'C', 'C'],
    ['D', 'D', 'D', 'D'],
];

// this array of values (with one extra of each value) would also return the same result
// because there aren't enough added values for a second combined group
var values = new[] { 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'D', 'D', 'D', 'D', 'D' };

最容易描述这种行为的用例可能就像一个视频游戏的制作菜单,你会看到“你需要1个A,2个B,3个C和4个D来制作这个项目”,所以你感兴趣的是你有多少个完整的值集,任何多余的都可以忽略。
我已经用Linq尝试过了,当所有字段所需的数量都相同时,我让它工作了,这显然不能满足所有用例。我不打算在这里发布我的代码尝试,因为我希望对这个问题有一个新的视角,但是如果它有帮助的话,我可以提供它。
先谢谢你,
标记

pxyaymoc

pxyaymoc1#

这个答案是基于这样一个假设,即结果可以简单地是一个完整集合的计数。
我建议从创建源数组内容的概述开始:每个字符出现多少次?这样一个概述的好工具将是一本字典。
首先,需要对源数组中的值进行分组。然后,可以基于这些分组创建一个字典。每个KeyValuePair的键将是char,而值将是该char的出现次数:

var countPerChar = values
    .GroupBy(_ => _)
    .ToDictionary(
        charGroup => charGroup.Key,
        charGroup => charGroup.Count());

如果您的源阵列为:

var values = new[] { 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'D', 'D', 'D', 'D', 'D' };

,则countPerChar看起来会像这样:
然后,我创建一个字典来存储每个字符的 * 完整集 * 的计数。这个字典应该包含与config一样多的条目(并且config中的所有键都应该存在)。
对于config中的每个条目,我将尝试从countPerChar中获取目标字符的值。
如果目标字符存在于countPerChar中,则可以将关联的字符计数除以所需的数量,以获得目标字符的 * 全集 *。
如果目标字符 * 不 * 存在于countPerChar中,则目标字符的 * 完整集 * 是0

var completeSetsPerChar = new Dictionary<char, int>();

foreach (var entry in config.Where(c => c.AmountRequired > 0))
{
    countPerChar.TryGetValue(entry.Value, out int charCount);
    
    completeSetsPerChar[entry.Value] = charCount / entry.AmountRequired;
}

现在,为了得到 * 完全集 * 的计数,你可以简单地取每个字符 * 的所有 * 完全集的最小值:

var completeSets = completeSetsPerChar.Values.Min();

例如小提琴here

eufgjt7s

eufgjt7s2#

我也有一个解决方案,它会告诉你一个集合是否完整:

// when given this list of required amounts
            var config = new[] {
                 new { Value= 'A', AmountRequired= 1 },
                new { Value = 'B', AmountRequired= 2 },
                new { Value = 'C', AmountRequired = 3 },
                new { Value= 'D', AmountRequired= 4 }
            };

            // and this array of values (matches requirements exactly)
            var values = new[] { 'A', 'B', 'B', 'C', 'C', 'C', 'D', 'D', 'D', 'D' };

            var res =
                       from cfg in config
                       select (new { cfg.Value, setComplete = (values.Count(x => x == cfg.Value) >= cfg.AmountRequired) });

            res.ToList().ForEach(x => Console.WriteLine(x));

相关问题