根据列表的值清除List with Linq中的一些属性值

时间:2015-01-07 09:45:14

标签: c# .net linq

我有一个对象“MyObject”,其中包含属性(所有字符串):“PropA”,“PropB”和“PropC”。

var List = new List();

我在此列表中添加了一个具有以下值的对象:

List.Add(new MyObject { PropA = "AA", PropB = "1", PropC = "TT"});
List.Add(new MyObject { PropA = "AA", PropB = "1", PropC = "TT"});
List.Add(new MyObject { PropA = "AA", PropB = "1", PropC = "TT"});

List.Add(new MyObject { PropA = "BB", PropB = "1", PropC = "TT"});
List.Add(new MyObject { PropA = "BB", PropB = "1", PropC = "TT"});

使用linq,我希望每个不同的“PropA”保留第一条记录,但设置为string.Empty另一条记录。我想要的结果是带有这些值的List:

MyObject { PropA = "AA", PropB = "1", PropC = "TT"}
MyObject { PropA = "", PropB = "", PropC = "TT"}
MyObject { PropA = "", PropB = "", PropC = "TT"}
MyObject { PropA = "BB", PropB = "1", PropC = "TT"}
MyObject { PropA = "", PropB = "", PropC = "TT"}

我使用foreach但是在Linq中可能会更清洁,但必须保留结果的顺序。

6 个答案:

答案 0 :(得分:4)

这适用于特定情况:

var list = 
 List.GroupBy(x => x.PropA)
        .SelectMany(grp => new MyObject[] { grp.First() }
        .Concat(grp.Skip(1)
          .Select(x => { x.PropA = String.Empty; x.PropB = String.Empty; return x; } )
           )
         );

LinqPad结果:

linqpad screenshot

作为旁注,我不认为在这种情况下使用Linq是合理的,它不会使代码更快或更清洁。必须使用可用的工具来编写更好,更高性能或更清晰的代码,但在这种情况下,我不认为这比foreach更好(至少是经过深思熟虑的foreach ,而不是以任何可能的方式蛮力。

答案 1 :(得分:1)

这个怎么样:

    var result = List.GroupBy(prop => prop.PropA)
        .SelectMany(group => new [] { group.First() }.Concat(group.Skip(1).Select(x => { x.PropA = x.PropB = ""; return x; }))).ToList();

答案 2 :(得分:0)

var groups = List.GroupBy(obj => obj.PropA);
foreach (var group in groups)
{
    foreach (var item in group.Skip(1))
    {
        item.PropA = "";
        item.PropB = "";
    }
}

答案 3 :(得分:0)

这个有趣问题的又一个解决方案:

var result =
    list
    .GroupBy(x => x.PropA, (key, items) => new { Key = key, Items = items })
    .Select(x => x.Items.Select((item, index) =>
    {
        if (index == 0) return item;
        item.PropA = string.Empty;
        item.PropB = string.Empty;
        return item;
    }))
    .SelectMany(x => x)
    .ToList();

它修改了每个组中的原始对象,但是第一个。这次没有Concat


有时候这完全取决于表现。如果有人担心这个问题就会遇到这个问题的答案是,在这种情况下,一个简单的循环比建议的linq查询快大约四倍:

对于1.000.000项,linq需要~200ms,而以下循环 ~45ms

string prev = list.First().PropA;
foreach (var item in list.Skip(1))
{
    if (item.PropA == prev)
    {
        item.PropA = string.Empty;
        item.PropB = string.Empty;
    }
    else
    {
        prev = item.PropA;
    }
}

答案 4 :(得分:-1)

没有LINQ

HashSet<string> propA = new HashSet<string>();
HashSet<string> propB = new HashSet<string>();

for (int i = 0; i < list.Count; i++)
{
    if (!propA.Add(list[i].PropA))
    {
        list[i].PropA = string.Empty;
    }

    if (!propB.Add(list[i].PropB))
    {
        list[i].PropB = string.Empty;
    }
}

答案 5 :(得分:-2)

此?

string currentValue = "";
            List.OrderBy(x => x.PropA).ToList()ForEach(x =>
            {
                if (string.IsNullOrEmpty(currentValue))
                {
                    // Assuming PropA will never be null
                    currentValue = x.PropA;
                    // this is first element
                    return;
                }
                if (x.PropA == currentValue)
                {
                    x.PropA = "";
                }
                else
                {
                    currentValue = x.PropA;
                }

            });