Mohammed Yasin
Mohammed Yasin

Reputation: 739

C# LINQ to merge two breakup

I am looking for simple LINQ to solve this:

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";

My alternate solution as follows

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;
    }
}

Upvotes: 0

Views: 163

Answers (4)

Rapha&#235;l Althaus
Rapha&#235;l Althaus

Reputation: 60493

If you don't need an ordering by value, you can simply do

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])))));

if you need ordering

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)));

Upvotes: 1

Mark Shevchenko
Mark Shevchenko

Reputation: 8197

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);

The code may contain syntax errors, cause I've not tested it.

Upvotes: 1

Frank
Frank

Reputation: 4481

    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);

Upvotes: 3

Matteo Mosca
Matteo Mosca

Reputation: 7448

Looking at the result I am assuming you add the values after the semicolon where the label before the semicolon match.

It can be treated as a little fun quiz, maybe more suited to another stackexchange site, but anyway.

This can be achieved with a simple (but not very short) linq expression:

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)

Upvotes: 0

Related Questions