2

My situation is this: I have a list of TFS change sets. Each change set has an ID, and a list of related work items. A work item has an ID, and a list of links, which are basically strings with change set ID's.

I want to have a list with the reverse hierarchy, meaning, I want to have a list of work items, and for each one a list of related change sets (and keep the ID field of both).

The structure now:

---chageset1
       |
       |-------workitem1
       |-------workitem2
---chageset2
       |
       |-------workitem2
       |-------workitem3

the structure I want

---workitem1
       |
       |-------chageset1
---workitem2
       |
       |-------chageset1
       |-------chageset2
---workitem3
       |
       |-------chageset2
  • Instead of your syntax for your structure, I suggest nesting them with tabs. On the top line, have ChangeSet1, and on the second line, add 4 spaces, and put WorkItem1, on the third line, 4 spaces and WorkItem2 so that WorkItem1 and WorkItem2 are straight up and down. The next line, ChangeSet2, would be back all the way to the left. It would be easier to understand. – seekerOfKnowledge Oct 17 '13 at 14:20
  • Oh, just saw Chad's edit. Thanks Chad. – seekerOfKnowledge Oct 17 '13 at 14:22
  • 1
    Post the declarations (Types) of the available datastructures. – H H Oct 17 '13 at 14:26
  • This is asked so many times. More like a pivoting action. One such: http://stackoverflow.com/questions/167304/is-it-possible-to-pivot-data-using-linq – nawfal Oct 20 '13 at 08:26

3 Answers3

2
WorkItem w1 = new WorkItem { Name = "w1" };
WorkItem w2 = new WorkItem { Name = "w2" };
WorkItem w3 = new WorkItem { Name = "w3" };
ChangeSet c1 = new ChangeSet { Name = "c1", WorkItems = new List<WorkItem> { w1 } };
ChangeSet c2 = new ChangeSet { Name = "c2", WorkItems = new List<WorkItem> { w3, w2 } };
ChangeSet c3 = new ChangeSet { Name = "c3", WorkItems = new List<WorkItem> { w3 } };
List<ChangeSet> changeSets = new List<ChangeSet> { c1, c2, c3 };
var result = changeSets
    .SelectMany(c => c.WorkItems)
    .Distinct()
    .ToDictionary(w => w,
                  w => changeSets.Where(c => c.WorkItems.Contains(w)));
foreach (var kvp in result)
{
    var workItem = kvp.Key;
    var changeSetsForWi = kvp.Value;
    Console.WriteLine(workItem.Name);
    foreach (var cs in changeSetsForWi)
    {
        Console.WriteLine("  " + cs.Name);
    }
}
nawfal
  • 70,104
  • 56
  • 326
  • 368
Ahmed KRAIEM
  • 10,267
  • 4
  • 30
  • 33
2

you could use linq to do this....

changesets.SelectMany(x => x.workitems.Select(y => new {
                                                         changeset = x.id,
                                                         workitem=y.id})
          .GroupBy(x => x.workitem)
          .Select(x => new {
                              workitem = x.Key, 
                              Changesets = x.Select(y = > y.changeset).ToArray()
                           }).ToArray();
Bob Vale
  • 18,094
  • 1
  • 42
  • 49
0
public class ChangeSet
{
  IList<WorkItem> WorkItems {get;set;};
}

public class WorkItem
{
  IList<ChangeSet> ChangeSets{get;set;};
}

It's fairly easy to do both then, iterate over your changesets or workitems and print out their contents.

foreach(var workitem in workItems)
{
  WriteOut(workItem);
  WriteOut(workItem.ChangeSets);
}
Carra
  • 17,808
  • 7
  • 62
  • 75
  • You're encouraging unnecessary duplication of information. Moreover: how could you possibly reconcile a ChangeSet that said it included WorkItem that did not say it belonged to that ChangeSet? – Andrew Coonce Oct 17 '13 at 16:14
  • Speed vs storage. There's a few more reference bytes but it will go faster than using a group by, selectmany & select. And of course, you have to fill them in correctly or it won't work. I think it's a logically consistent Domain Model. A changeset has workitems, a workitem has changesets, simple as that. – Carra Oct 18 '13 at 13:01