我有一个对象“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中可能会更清洁,但必须保留结果的顺序。
答案 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结果:
作为旁注,我不认为在这种情况下使用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;
}
});