4

I have such class:

public class Foo
{
  public string Regn{get;set;}

  public string DocName{get;set;}

  ...
}

In the my application this class uses with IEnumerable:

IEnumerable<Foo> items;

How to get new IEnumerable, where for all items with the same Regn and DocName property DocName sets like this(only if objects with same DocName >1):

item.DocName=item.DocName+".1";//+"2",etc.

[UPDATE] Input sample:

Regn DocName
1    1
1    2
1    2
2    5
2    5
2    6

Output:

Regn DocName
1    1
1    2.1
1    2.2
2    5.1
2    5.2
2    6
Anton Kandybo
  • 3,678
  • 4
  • 23
  • 31

4 Answers4

2

If you have a default constructor for Foo try to use this:

var newItems = items.
            GroupBy(f => Tuple.Create(f.Regn, f.DocName)).
            SelectMany(gr => gr.Count()<=1 ? gr : gr.Select((f, i) => new Foo
            {
                Regn = f.Regn,
                DocName = f.DocName + "." + (i + 1)
            }));
default locale
  • 13,035
  • 13
  • 56
  • 62
1

You can group with LINQ and cast out groups that only have one item, then iterate over the items in each group to set the DocName:

// Group and filter
var groups = items.GroupBy(i => new { i.Regn, i.DocName })
                  .Where(g => g.Count() > 1);

// Iterate over each group with many items
foreach (var g in groups) {
    var itemsInGroup = g.ToArray();
    // Iterate over the items and set DocName
    for (var i = 0; i < itemsInGroup.Length; ++i) {
        itemsInGroup[i].DocName = g.Key + "." + (i + 1);
    }
}
Rune FS
  • 21,497
  • 7
  • 62
  • 96
Jon
  • 428,835
  • 81
  • 738
  • 806
0

All in one statement, just for fun.

var query = items.GroupBy(i => new { i.DocName, i.Regn })
    .SelectMany(group => 
        {
            int itemNum = 0;
            return group.Select(item =>
                {
                    var suffix = itemNum > 0 ? ("." + itemNum) : "";
                    var newDocName = item.DocName + suffix;
                    itemNum++;
                    return new { item, NewDocName = newDocName };
                });
        });
Kirk Broadhurst
  • 27,836
  • 16
  • 104
  • 169
-1

Or use a LINQ statement to create a new result set like:

var fixedSet = from entry in existing
               group entry by entry.DocName + entry.Regn into groupedEntries
               let groupedEntriesAsArray = groupedEntries.ToArray()
               from groupedEntry in groupedEntriesAsArray
               let index = Array.IndexOf(groupedEntriesAsArray, groupedEntry)
               select new Foo
               {
                   DocName =
                       string.Format("{0}.{1}", groupedEntry.DocName, index + 1),
                   Regn =
                       string.Format("{0}.{1}", groupedEntry.Regn, index + 1)
               };
Yuck
  • 49,664
  • 13
  • 105
  • 135
Polity
  • 14,734
  • 2
  • 40
  • 40
  • I'm not a downvoter but some problems in your code: 1. Is not readable, 2. instead of `Array.IndexOf(groupedEntriesAsArray, groupedEntry)` you can use `Select` with indexer, your current approach is not good when performance issue is important also it's depend on equality implementation of class, may be cause same values for different objet. I think MAKKAM answer is best one in this case. – Saeed Amiri Sep 27 '11 at 07:54
  • @Saeed Amiri: Thanks. I'm aware of the negative attributes using this approach, but i have to disagree on the readablity. I gave this example because no other answer introduced a query syntax like linq statement. The way i read it, it makes perfect sence and is the most readable (compared to others). But ofcourse this is a personal taste – Polity Sep 27 '11 at 07:59
  • As you said it seems to be personal taste, but in all dot Notation prefered to query syntax in linq except in some cases see http://stackoverflow.com/questions/630045/linq-dot-notation-vs-query-expression for discussion about this. – Saeed Amiri Sep 27 '11 at 08:16
  • @Polity, your code is readable enough, but I totally agree with Saeed about performance issues. Also I think it's not a good idea to group by concatenation of Regn and DocName. Check out foo1 = new Foo{Regn="c", DocName="ab"} and foo2 = new Foo{Regn="bc", DocName="a"}. Your query will place both of them in one group. – default locale Sep 27 '11 at 11:05