有没有一种方法可以对多个值进行排序,并只保留每个值中的最大值?

时间:2019-03-25 17:11:42

标签: c# .net sorting

我有一些代码可以生成位置类型和最大数量的输出。

我只想保留这些值的每种组合中的最大值。但是我不确定会允许n个位置的最佳方法。

当前生成数据并将其存储为字符串列表,并在位置之间留有空格。

var locationOutputDistinct = new List<string>
{
"PERSON:2 ",
"PERSON:1 SCOOTER:1 ",
"PERSON:1 BIKE:1 ",
"PERSON:2 BIKE:1 ",
"PERSON:1 BIKE:1 SCOOTER:1 ",
"PERSON:3 ",
"PERSON:3 BIKE:1 ",
"PERSON:4 ",
"PERSON:4 BIKE:1 ",
"PERSON:2 SCOOTER:1 ",
"PERSON:5 ",
"PERSON:3 SCOOTER:1 ",
"PERSON:6 "
};

理想的输出如下所示:

PERSON:1 BIKE:1 SCOOTER:1 
PERSON:4 BIKE:1 
PERSON:3 SCOOTER:1 
PERSON:6 

表示您可以有6个人,或者3个人和一辆小型摩托车,或者4个人和一辆自行车,或者1个人,1个自行车和1个滑板车。它们各自类型的最大组合。

最好的方法是什么?

还有其他一些数据集和预期结果。 https://justpaste.it/6cce5

这是一个直观的示例,并解释了我要制作的内容。 https://justpaste.it/4vqu2

4 个答案:

答案 0 :(得分:1)

基于2个课程

public class Res{
    public string Key;
    public int Val;
}
public class Reduced
{
    public string Key;
    public IEnumerable<Res>[] invalid;
}

您可以使用此代码汇总结果。

    var loc =
   locationOutputDistinct
   .Select(x => x.Trim().Split(' ').ToArray()
   .Select(
       y => {
           var kv = y.Split(':');
           return new Res()
           {
               Key = kv[0],
               Val = int.Parse
                (kv[1])
           };
       }).ToArray()).ToArray()

    .GroupBy(x =>
       String.Join(",",
       x.Select(y => y.Key))
       );

然后您必须应用归约规则

    var reduced = 
    loc.Select(x => new Reduced() {
    Key = x.Key,                 
            invalid =
                x.Where(y => loc.Any(ext => ext.Any(xsup =>
                   y.All(z => xsup.Any(xsupcell => xsupcell.Key == z.Key)) &&
                   y.All(z =>
                   z.Val <= xsup
                         .Where(xsupcell =>
                   xsupcell.Key == z.Key)
                         .First().Val) &&
                         ((xsup.Length > y.Length) ||
                   y.Any(z =>
                   z.Val < xsup
                         .Where(xsupcell =>
                   xsupcell.Key == z.Key)
                         .First().Val))

                    ))).ToArray()
                            });

    var remain = loc.Select(x => x.Where(y =>
    !reduced.Where(r => r.Key == x.Key).SelectMany(r2 => r2.invalid).Any(r3 => r3.All(r4 =>
    y.Any(y2 => y2.Key == r4.Key && y2.Val == r4.Val)))));

从您的上一个示例中,我看到您也希望减少扩展的组合y和扩展的组合(xsup.Length > y.Length),因此我在上面的代码中包括了最后一个功能。 / p>

这时您需要打开包装并打印结果。

    foreach (var x in remain)
        Console.WriteLine
        (//x.Key+": " +
          String.Join("\n",
          x.Select(y =>
          String.Join(" ",
          y.Select(z => z.Key + ":" + z.Val)
              ))));

从问题的原始顺序中您将获得

PERSON:6
PERSON:3 SCOOTER:1
PERSON:4 BIKE:1
PERSON:1 BIKE:1 SCOOTER:1

和来自

"AM:4 SC:1 ",
"AM:4 WC:1 ",
"AM:4 WC:1 SC:1 ",
"AM:4 WC:2 ",
"AM:4 WC:2 SC:1 ",
"AM:5 ",
"AM:5 WC:1 ",
"AM:6 ",
"AM:6 WC:1 ",
"AM:7 ",
"AM:8 "

你会得到

AM:6 WC:1
AM:4 WC:2 SC:1
AM:8

提琴Command `npm start` does nothing

答案 1 :(得分:0)

以下作品:

            var locationOutputDistinct = new List<string>
            {
                "FRNT:2 REAR:1 ",
                "FRNT:2 ROOF:1 ",
                "FRNT:2 ROOF:1 REAR:1 ",
                "FRNT:3 ",
                "FRNT:3 REAR:1 ",
                "FRNT:4 ",
                "FRNT:4 REAR:1 ",
                "FRNT:3 ROOF:1 ",
                "FRNT:5 ",
                "FRNT:4 ROOF:1 ",
                "FRNT:6 ",
                "FRNT:5 ROOF:1 ",
                "FRNT:7 ",
                "FRNT:6 ROOF:1 ",
                "FRNT:8 "
            };
            var parsedData = locationOutputDistinct
                .Select(x => x.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
                    .Select(y => new KeyValuePair<string, int>(y.Substring(0, y.IndexOf(":")), int.Parse(y.Substring(y.IndexOf(":") + 1)))).OrderBy(z => z.Key).ToList())
                    .ToList();

            var groups = parsedData
                .GroupBy(x => string.Join("^", x.Select(y => y.Key)))
                .ToList();

            var results = groups.Select(x => x.SelectMany(y => y).GroupBy(z => z.Key).Select(z => new { Key = z.Key, Value = z.Max(a => a.Value)}).ToList()).ToList();
            List<string> strings = results.Select(x => string.Join(" ", x.Select(y => y.Key + ":" + y.Value.ToString()))).ToList();

答案 2 :(得分:0)

下面的LINQ查询将为您提供预期的结果。首先,我们将名称按数字进行分组,因为它们将始终相同。然后,我们遍历分组并计算需要匹配的最大和,最后,我们从该组中获得具有匹配和的记录。

var groupedLocation = locationOutputDistinct.GroupBy(x => new string(x.Where(c => !char.IsDigit(c)).ToArray()))
                                            .OrderByDescending(x => x.Key.Length)
                                            .ToList();

foreach(var group in groupedLocation)
{
    var maxSum = group.Max(x => x.Where(c => char.IsDigit(c))
                      .Select(z => char.GetNumericValue(z)).Sum());
    var matchingRecord = group.FirstOrDefault(x => x.Where(c => char.IsDigit(c)).Select(z => char.GetNumericValue(z)).Sum() == maxSum);

    Console.WriteLine(matchingRecord);
}

输出

enter image description here

答案 3 :(得分:0)

我提供此解决方案的原因是我的输出与您的示例输出不匹配。那是因为我不同意您的输出。

例如,您拥有的一个输出示例提供了以下内容:

OUTPUT:
AM:10 BK:1 
AM:8 BK:1 BWC:1 
AM:8 BK:1 WC:1 
AM:7 BK:1 SC:1
AM:6 BK:1 BWC:2 
AM:6 BK:1 BWC:1 WC:1 
AM:6 BK:1 WC:2 
AM:5 BK:1 BWC:1 SC:1
AM:5 BK:1 WC:1 SC:1
AM:4 BK:1 BWC:2 WC:1 
AM:4 BK:1 WC:3 
AM:4 BK:1 SC:2
AM:2 BK:1 WC:1 SC:2

但是AM:4 BK:1 WC:3小于AM:8 BK:1 WC:1,因此我不认为这两个都是结果,并且有多个示例。话虽如此,这是我的解决方案,它为每种可能的输入组合获取绝对最大值。

执行:

        // Get all the `keys` in the location output
        var keys = GetKeys(locationOutputDistinct);
        // Get the possible combinations of keys
        var combinations = GetCombination(keys);

        var maxCombos = new List<string>();

        foreach (var combo in combinations)
        {
            var maxOfCombo = GetMaxOfCombo(locationOutputDistinct, combo);
            if (maxOfCombo.Any())
            {
                maxCombos.AddRange(maxOfCombo);
            }
        }

        maxCombos = maxCombos.Distinct().ToList();
        maxCombos.Sort();
        foreach (var maxCombo in maxCombos)
        {
            Console.WriteLine(maxCombo);
        }

以及支持方法:

        /// <summary>
    /// Get the keys from the input and return it in a `;` delimited string
    /// </summary>
    /// <param name="vals">Input list</param>
    /// <returns></returns>
    public static List<string> GetKeys(List<string> vals)
    {
        var keys = new List<string>();
        foreach (var grouping in vals)
        {
            var parameters = grouping.Split(' ');
            foreach (var parameter in parameters)
            {
                var paramVals = parameter.Split(':');
                var label = paramVals[0].Trim();
                if (!string.IsNullOrEmpty(label) && !keys.Contains(label))
                {
                    keys.Add(label);
                }
            }
        }

        return keys;
    }

    /// <summary>
    /// Take all the keys and return all possible combinations of them
    /// </summary>
    /// <param name="list">List of keys</param>
    /// <returns></returns>
    public static List<string> GetCombination(List<string> list)
    {
        var combos = new List<string>();
        var comb = "";
        double count = Math.Pow(2, list.Count);
        for (int i = 1; i <= count - 1; i++)
        {
            var sep = "";
            string str = Convert.ToString(i, 2).PadLeft(list.Count, '0');
            for (int j = 0; j < str.Length; j++)
            {
                if (str[j] == '1')
                {
                    comb += sep + list[j];
                    sep = ";";
                }
            }

            combos.Add(comb);
            comb = "";
        }

        return combos;
    }

    /// <summary>
    /// Return the combinations that have the largest values
    /// </summary>
    /// <param name="source">String list of input</param>
    /// <param name="combo">`;` delimited keys you're checking</param>
    /// <returns></returns>
    public static List<string> GetMaxOfCombo(List<string> source, string combo)
    {
        var comboKeys = combo.Split(';');
        var matchingCombos = source.Where(s => comboKeys.All(a => s.IndexOf(a) != -1) && s.Trim().Split(' ').Length == comboKeys.Count());

        // Return empty set if there were none
        if (!matchingCombos.Any())
        {
            return new List<string>();
        }

        var comboValues = matchingCombos.Select(mc => new
        {
            // Get the value sum of the individual keys
            value = mc.Split(' ').Where(w => !string.IsNullOrEmpty(w.Trim())).Sum(s => int.Parse(string.Concat(s.Where(c => char.IsDigit(c))))),
            label = mc
        });
        // Get the max value
        var max = comboValues.Max(m => m.value);
        // Get all that have the same max
        var maxCombos = comboValues.Where(f => f.value == max);

        if (!maxCombos.Any())
        {
            return new List<string>();
        }
        return maxCombos.Select(s => s.label).ToList();
    }

这是一个有效的示例:https://dotnetfiddle.net/mwpkMO