C# LINQ 合并两个分手

C# LINQ to merge two breakup

我正在寻找简单的 LINQ 来解决这个问题:

string[] breakups = new[]
{
    "YQ:50/BF:50/YR:50",
    "YQ:50/SR:50",
    "YQ:50/BF:50/YR:50",
    "XX:00 .... and so on"
};

// LINQ expression

string expectedResult = "YQ:150/BF:100/YR:100/SR:50";

我的备选方案如下

public static string CalcRTBreakup(string pstrBreakup)
{
  string lstrBreakup = pstrBreakup;
    try
    {
        string[] lstrArrRB = lstrBreakup.Split('@');
        string[] lstrArrBreakupSplit = new string[lstrBreakup.Split('@')[0].Split('|').Length];
        for (int count = 0; count < lstrArrRB.Length; count++)
        {
            string[] lstrArrtemp = lstrArrRB[count].Split('|');
            for (int countinner = 0; countinner < lstrArrtemp.Length; countinner++)
            {
                if (string.IsNullOrEmpty(lstrArrBreakupSplit[countinner]))
                    {
                        if (string.IsNullOrEmpty(lstrArrtemp[countinner]))
                            continue;
                        lstrArrBreakupSplit[countinner] = lstrArrtemp[countinner];
                    }
                    else
                    {
                        if (string.IsNullOrEmpty(lstrArrtemp[countinner]))
                            continue;
                        lstrArrBreakupSplit[countinner] += "/" + lstrArrtemp[countinner];
                    }
                }
            }
            for (int count = 0; count < lstrArrBreakupSplit.Length; count++)
            {
                if (string.IsNullOrEmpty(lstrArrBreakupSplit[count]))
                    continue;
                lstrArrBreakupSplit[count] = CalcRTBreakupDict(lstrArrBreakupSplit[count].TrimEnd('/')).TrimEnd('/');
            }
            lstrBreakup = string.Empty;
            foreach (string strtemp in lstrArrBreakupSplit)
            {
                lstrBreakup += strtemp + '|';
        }
        return lstrBreakup;
    }
    catch (Exception)
    {
        return "";
    }
}
public static string CalcRTBreakupDict(string pstrBreakup)
{
    string lstrBreakup = pstrBreakup;
    Dictionary<string, double> ldictDreakup = new Dictionary<string, double>();
    try
    {
        lstrBreakup = lstrBreakup.TrimEnd('/').Trim();
        string[] lstrArrBreakup = lstrBreakup.Split('/');
        foreach (string strBr in lstrArrBreakup)
        {
            string[] lstrBreakupCode = strBr.Split(':');
            if (!ldictDreakup.Keys.Contains(lstrBreakupCode[0]))
            {
                double lintTemp = 0; double.TryParse(lstrBreakupCode[1], out lintTemp);
                ldictDreakup.Add(lstrBreakupCode[0], lintTemp);
            }
            else
            {
                double lintTemp = 0; double.TryParse(lstrBreakupCode[1], out lintTemp);
                lintTemp = lintTemp + ldictDreakup[lstrBreakupCode[0]];
                ldictDreakup.Remove(lstrBreakupCode[0]);
                ldictDreakup.Add(lstrBreakupCode[0], lintTemp);
            }
        }
        lstrBreakup = string.Empty;
        foreach (string dictKey in ldictDreakup.Keys)
        {
            lstrBreakup += dictKey + ":" + ldictDreakup[dictKey] + "/";
        }
        return lstrBreakup;
    }
    catch (Exception)
    {
        return pstrBreakup;
    }
}

查看结果,我假设您在分号之后添加的值与分号之前的标签匹配。

它可以被视为一个有趣的小测验,也许更适合另一个 stackexchange 站点,但无论如何。

这可以通过一个简单(但不是很短)的 linq 表达式来实现:

breakups
    .Select(c => c.Split('/'))
    .SelectMany(c => c)
    .Select(c => new
            {
                Label = c.Split(':')[0],
                Value = Convert.ToInt32(c.Split(':')[1])
            })
    .GroupBy(c => c.Label)
    .Select(c => new
            {
                Label = c.Key,
                Value = c.Sum(x => x.Value)
            })
    .OrderByDescending(c => c.Value)
    .Select(c => c.Label + ":" + c.Value)
    .Aggregate((s1,s2) => s1 + "/" + s2)
    string[] breakups =
    {
        "YQ:50/BF:50/YR:50",
        "YQ:50/SR:50",
        "YQ:50/BF:50/YR:50",
        "XX:00"
    };

    var groups = from line in breakups           // these are our items in the array
                 from item in line.Split('/')    // each one will be split up at '/'
                 let pair = item.Split(':')      // each pair is split at ':'
                 let key = pair[0]               // our key is the first item...
                 let value = int.Parse(pair[1])  // and the value is the second
                 group value by key              // let's group by key
                 into singleGroup
                 let sum = singleGroup.Sum()     // and build each group's sum
                 where sum > 0                   // filter out everything <= 0
                 select singleGroup.Key + ":" + sum;  // and build the string

    var result = string.Join("/", groups);
var sums = breakups.SelectMany(breakup => breakup.Split('/'))
                   .Select(s => new { Code = s.Substring(0, 2), Value = int.Parse(s.Substring(2)) })
                   .GroupBy(pair => pair.Code)
                   .Select(group => string.Format("{0}/{1}", group.Key, group.Sum(x => x.Value)));

string result = string.Join("/", sums);

代码可能包含语法错误,因为我没有测试它。

如果您不需要按值排序,您可以简单地执行

var res = string.Join("/", breakups
                              .SelectMany(m => m.Split('/'))
                              .Select(x => x.Split(':'))
                              .GroupBy(m => m[0])
                              .Select(m => string.Format("{0}:{1}", m.Key, m.Sum(g => Int32.Parse(g[1])))));

如需订购

var res = string.Join("/", breakups
                              .SelectMany(m => m.Split('/'))
                              .Select(x => x.Split(':'))
                              .GroupBy(m => m[0])
                              .Select(m => new
                              {
                                  key = m.Key,
                                  val = m.Sum(g => Int32.Parse(g[1]))
                              })
                              .OrderByDescending(m => m.val)
                              .Select(m => string.Format("{0}:{1}", m.key, m.val)));