Лучший способ изменить свойство элементов в списке в соответствии с группировкой - PullRequest
2 голосов
/ 20 ноября 2011

У меня есть List из CartItem, некоторые из которых имеют идентичные Name свойства.Мне нужно, чтобы все свойства Name были уникальными.Очевидная вещь, которую нужно сделать, это свернуть их в отдельные элементы с Quantity properties> 1, но по причинам, в которые я не буду вдаваться, я не свободен это делать.Я также не хочу делать некрасивую, простую вещь, просто добавляя GUID к каждому имени.Поэтому я хочу добавить к свойствам Name подстроку типа "(1 из 3)", но только для имен, которые имеют дубликаты.Имена, которые уже являются уникальными, я хочу оставить в покое, поэтому ни одно из них не говорит "(1 из 1)".

Вот модульный тест того, о чем я говорю.Я пытаюсь найти лучший способ сделать строки между комментариями:

class CartItem
{
   public string Name { get; set; }
   public int Quantity { get; set; }
   public decimal UnitPrice { get; set; }
}

[TestMethod]
public void TestSOQuestion()
{
   var exampleList = new List<CartItem>
   {
      new CartItem 
         { Name="Same String", UnitPrice=10.00m, Quantity=1},
      new CartItem 
         { Name="Same String", UnitPrice=10.00m, Quantity=1},
      new CartItem 
         { Name="Other String", UnitPrice=14.99m, Quantity=1},
      new CartItem 
         { Name="Other String", UnitPrice=14.99m, Quantity=1},
      new CartItem 
         { Name="Other String", UnitPrice=14.99m, Quantity=1},
      new CartItem 
         { Name="Only One Of This", UnitPrice=29.99m, Quantity=1}
   };

var expectedList = new List<CartItem>
   {
      new CartItem 
        { Name="Same String (1 of 2)", UnitPrice=10.00m, Quantity=1},
      new CartItem 
        { Name="Same String (2 of 2)", UnitPrice=10.00m, Quantity=1},
      new CartItem 
        { Name="Other String (1 of 3)", UnitPrice=14.99m, Quantity=1},
      new CartItem 
        { Name="Other String (2 of 3)", UnitPrice=14.99m, Quantity=1},
      new CartItem 
        { Name="Other String (3 of 3)", UnitPrice=14.99m, Quantity=1},
      new CartItem 
        { Name="Only One Of This", UnitPrice=29.99m, Quantity=1}
   };

        //This is the best I can come up with:
        var groups = exampleList.GroupBy(item => item.Name)
                     .Where(g => g.Count() > 1);
        foreach (var group in groups)
        {
            int i = 1;
            foreach (var item in group)
            {
                item.Name = item.Name + string.Format(
                               " ({0} of {1})", i++, group.Count());
            }
        }
        //Is there a better way to do this?

        for (int i = 0; i < expectedList.Count(); i++)
        {
            Assert.AreEqual(expectedList[i].Name, exampleList[i].Name);
        }
    }

Ответы [ 2 ]

2 голосов
/ 20 ноября 2011
var result=exampleList.GroupBy(p=>p.Name).SelectMany(p=>p.Select((value,index)=> new CartItem()
            {
                Name = value.Name +
                       (p.Count() == 1?"": string.Format(" ({0} of {1})", index+1, p.Count())),
                UnitPrice=value.UnitPrice,
                Quantity=value.Quantity,
            }
            )).ToList();
0 голосов
/ 24 ноября 2011

Спасибо RedHat за вдумчивый ответ.

Вот что я в итоге использовал:

exampleList.GroupBy(item => item.Name)
    .Where(g => g.Count() > 1).ToList().ForEach
(
    group =>
    {
        foreach (var item in group
            .Select((x, i) => new { val = x, idx = i + 1 }))
        {
            item.val.Name += string.Format
            (
                " ({0} of {1})", item.idx, group.Count()
            );
        }
    }
);

Вместо того, чтобы проецировать результат на новый List, я предпочел выборочное изменение свойств Name в существующей коллекции. Поскольку фактический набор данных имеет в основном неповторяющиеся свойства Name который будет исключен Where(g => g.Count() > 1), будет меньше итераций через вложенные циклы foreach. Более того, этот класс Cart был значительно упрощен ради вопрос; на самом деле он содержит гораздо больше свойств, в том числе Dictionary пар имя-значение. Необходимость проецировать каждое свойство в результате будет означать более тесную связь с классом Cart. Если бы мы добавили или изменили свойство в будущем, этот код должно быть также обновлено. Чтобы избежать этой проблемы обслуживания, этот подход требует только существование свойства string Name.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...