Linq判断List>中的重复项

活着生活 2012-10-22 05:29:36
导入Excel之前要检查一遍,看是否有重复的行等错误,多个模块有导入功能,我就想干脆写下面这样一个类,用来记录待导入文件中的错误:


public class ImportLog
{
/// <summary>
/// Excel行号
/// </summary>
public int RowID { get; set; }

/// <summary>
/// 当前行中每个单元格的值
/// </summary>
public List<object> FieldList { get; set; }

/// <summary>
/// 是否包含错误
/// </summary>
public bool HasError { get; set; }

/// <summary>
/// 错误信息
/// </summary>
public string ErrorMsg { get; set; }
}

先拿“检查重复的行”来试试:


public List<ImportLog> GetRepeatedRows(List<ImportLog> list = null)
{
if (list == null)
{
list = new List<ImportLog>()
{
new ImportLog(){ RowID=1, FieldList=new List<object>(){"1","11","111"}, ErrorMsg=""},
new ImportLog(){ RowID=2, FieldList=new List<object>(){"1","11","111"}, ErrorMsg=""},
new ImportLog(){ RowID=3, FieldList=new List<object>(){"1","11","111","1111"}, ErrorMsg=""},
new ImportLog(){ RowID=4, FieldList=new List<object>(){"1","11","111","1112"}, ErrorMsg=""},
new ImportLog(){ RowID=5, FieldList=new List<object>(){"1","11","112","1121"}, ErrorMsg=""},
new ImportLog(){ RowID=6, FieldList=new List<object>(){"1","11","112","1121"}, ErrorMsg=""},
new ImportLog(){ RowID=7, FieldList=new List<object>(){"1","12","121","1211"}, ErrorMsg=""},
new ImportLog(){ RowID=8, FieldList=new List<object>(){"1","12","122","1221"}, ErrorMsg=""},
new ImportLog(){ RowID=9, FieldList=new List<object>(){"1","13","131","1311"}, ErrorMsg=""},
new ImportLog(){ RowID=10, FieldList=new List<object>(){"2","21","211","2111"}, ErrorMsg=""},
new ImportLog(){ RowID=11, FieldList=new List<object>(){"2","21","211","2111"}, ErrorMsg=""},
new ImportLog(){ RowID=11, FieldList=new List<object>(){"2","21","211","2111"}, ErrorMsg=""},
};
}
//方式1:成功,但效率貌似不高
//var ret1 = list.FindAll(a => list.FindAll(b => b.FieldList.Intersect(a.FieldList).Count() == a.FieldList.Count).Count > 1);

//方式2:group by m.FieldList into g 失败
var ret2 = (from t in list
where (
from d in
(
from m in list
group m by m.FieldList into g
where g.Count() > 1
select g
)
select d.Key
).Contains(t.FieldList)
select t).ToList();
var count = ret2.Count;//count=0 ……

return ret2;

}

各位大神,谁能给优化一下方式1,再给改改方式2?
拜谢!

呃,准备下班了,明天上午来了给分,见谅……
...全文
576 9 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
活着生活 2012-10-24
  • 打赏
  • 举报
回复
ok,结贴!
多谢Tim兄和sad_4978兄捧场!
q107770540 2012-10-23
  • 打赏
  • 举报
回复
取出所有重复的行:
var ret2=(from l in list
group l by string.Join(",",l.FieldList.OrderBy(x=>x).Select(x=>x.ToString()).ToArray()) into g
where g.Count()>1
from x in g
select x).ToList();
活着生活 2012-10-23
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 的回复:]

引用 1 楼 的回复:

C# code
var ret2=list.GroupBy(l=>string.Join(",",l.FieldList.OrderBy(x=>x).Select(x=>x.ToString()).ToArray()))
.Where(g=>g.Count()>1);

var ret2=(from l in list
group l ……
[/Quote]
Tim兄,你这个不太符合我的规则啊,我是要把【重复的行】取出来……
所以:

listRet = (from l in list
group l by string.Join(",", l.FieldList.OrderBy(x => x).Select(x => x.ToString()).ToArray()) into g
where g.Count() > 1//有“重复”的行
from x in g
select x).ToList();

然后,另外那个有点错,我也改了改:

var listRepeat = list.GroupBy(L => string.Join(",", L.FieldList.OrderBy(x => x))).Where(c => c.Count() > 1).Select(G => G.First()).ToList();
listRepeat.ForEach(m => listRet.AddRange(list.FindAll(r => r.FieldList.SequenceEqual(m.FieldList))));

呃,后面如果没人回复的话,我就再说不了话了吧?
那如果再没人来,就结贴了,上面两位兄弟都有分
活着生活 2012-10-23
  • 打赏
  • 举报
回复
我一朋友还给了另外一种写法,但是,效率更低……

var listRet = list.Where(m => list.Count(c => c.FieldList.SequenceEqual(m.FieldList)) > 1).ToList();

活着生活 2012-10-23
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 的回复:]

我尝试也写了一个,不知道符不符合要求。

var result = list.GroupBy(L => L.RowID).Select(G => G.First()).ToList();
[/Quote]
呃,忘了说明一下了:List<object> FieldList,代表的是Excel一行中的单元格,只要这个属性相同,就视为重复的行,行号只是用来标记,不计入判断……
而且,既然是检查Excel文件里的重复的行,那么不能只是把重复的内容找到,还要找到文件里都有哪些行是重复的。
所以,你这个似乎可以改一下:


var listRepeat = list.GroupBy(L => L.FieldList).Select(G => G.First()).ToList();
listRet.FindAll(l => listRepeat.FindAll(r => l.FieldList.SequenceEqual(r.FieldList)).Count > 1);

q107770540 2012-10-23
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]

C# code
var ret2=list.GroupBy(l=>string.Join(",",l.FieldList.OrderBy(x=>x).Select(x=>x.ToString()).ToArray()))
.Where(g=>g.Count()>1);
[/Quote]
var ret2=(from l in list
group l by string.Join(",",l.FieldList.OrderBy(x=>x).Select(x=>x.ToString()).ToArray()) into g
from x in g
select x).ToList();
sad_4978 2012-10-23
  • 打赏
  • 举报
回复
我尝试也写了一个,不知道符不符合要求。

var result = list.GroupBy(L => L.RowID).Select(G => G.First()).ToList();
活着生活 2012-10-23
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]

C# code
var ret2=list.GroupBy(l=>string.Join(",",l.FieldList.OrderBy(x=>x).Select(x=>x.ToString()).ToArray()))
.Where(g=>g.Count()>1);
[/Quote]
谢了,是个思路。
呃,不过,我是想最终得到一个List<ImportLog>,按照你这样GroupBy()之后得到的是一个IEnumerable<IGrouping<string, ImportLog>>,然后还要遍历list。有个更精简点的办法没?
q107770540 2012-10-22
  • 打赏
  • 举报
回复
var ret2=list.GroupBy(l=>string.Join(",",l.FieldList.OrderBy(x=>x).Select(x=>x.ToString()).ToArray()))
.Where(g=>g.Count()>1);

8,494

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 LINQ
社区管理员
  • LINQ
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧