基于列表中的一个值,使用Linq清除列表中一些属性的值

3

我有一个名为"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",保留第一条记录但将其他记录设置为空字符串。 我想要的结果是一个包含以下值的列表:

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 可能会更简洁,但结果的顺序必须保持不变。


2
我不确定我是否正确理解了你的问题,所以我只会把这个作为评论发布:你是指这个吗:List.GroupBy(prop => prop.PropA).Select(group => group.First()) - SBI
4
为什么修改了PropB,但没有修改PropC(即"clean"是什么意思)?您能用一些伪代码展示您试图做什么吗? - default
1
@SBI:我也曾这样想,直到看到期望的结果。原帖作者仍然想获取所有对象,除了组中的第一个对象“清理”... - Christoph Fink
1
那么,你能解释一下“clean”的意思吗? - default
3
继续使用 foreach。使用 LINQ 不会更加简洁,因为它不是用来改变/操作对象的,而是用于查询。使用 LINQ 获取想要的项目,然后使用 foreach 进行更改。如果您想保持原始顺序,这是最好的方法。 - Selman Genç
显示剩余5条评论
6个回答

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 截图

顺便说一句,我认为在这种情况下使用 Linq 是没有必要的,它并不能使代码更快或更清晰。我们必须利用现有工具编写更好、更高效、更清晰的代码,但在这种情况下,我认为无论如何使用 foreach(至少是一个经过深思熟虑的 foreach,而不是一个暴力的 foreach )都比使用 Linq 更好。


结果必须尊重第一项的顺序,就像列表中的第二和第三项“清空”(string.empty)一样,下一行与第4个条目相同,第5个被清除而不是全部清除,然后是另外两个。 - TheBoubou
但这并不会将属性设置为 String.Empty,而是创建新的对象... - t3chb0t
这个问题有很多解决方案。我也发布了一个 ;-] 尽管它与你的相似,但没有使用 Concat - t3chb0t
我真的不认为Linq是这个问题的解决方案(正如我在侧记中所述),但如果OP想要Linq,那就这样吧 :-) - Jcl
1
你在那里有一个语法错误。有一个多余的 }。这个编辑太小了,系统不会接受。我喜欢 LINQ 的原因是它很容易分组。 - t3chb0t
显示剩余3条评论

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

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

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 需要约 200 毫秒,而下面的循环仅需要约 45 毫秒:
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;
    }
}

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

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

            });

2
我用了foreach,但是用Linq可能会更简洁一些。 - Selman Genç
...只有在所有的"AA"都连续出现时才有效,但是一旦中间有一个"BB",结果中将会出现两个"AA"。 - Christoph Fink
1
@Kris-I,使用LINQ你不会得到更干净的东西。你最终将使用多个扩展方法。如果你觉得这更干净,那就去做吧。 - danish

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接