假设我有一份清单清单。 对于此列表中的每个项目,我都有一个自定义对象列表。
这些对象是这样的:
public string Field1
public string Field2
public string Field3
我想通过Linq实现:从我的列表列表中过滤掉所有具有相同三个字段的对象,这些字段不是列表中的第一个元素,只保留第一个元素。
因此,假设我的列表中有两个列表listA和列表B.
listA有三个对象object1,object2和object3。
object1.Field1 = "a" object1.Field2 = "A" object1.Field3 = "1"
object2.Field1 = "a" object2.Field2 = "B" object2.Field3 = "2"
object3.Field1 = "a" object3.Field2 = "C" object3.Field3 = "3"
listB有三个对象object4,object5和object6。
object4.Field1 = "a" object4.Field2 = "A" object4.Field3 = "1"
object5.Field1 = "a" object5.Field2 = "B" object5.Field3 = "2"
object6.Field1 = "a" object6.Field2 = "D" object6.Field3 = "3"
在此示例中,object1和object4是相同的,但由于它们是各自列表中的第一个,因此它们不会被过滤掉。 但是,object2和object5具有相同的三个字段值,只保留其中一个,以便在我的过程结束时,我将有两个列表如下:
listA有三个对象object1,object2和object3。
object1.Field1 = "a" object1.Field2 = "A" object1.Field3 = "1"
object2.Field1 = "a" object2.Field2 = "B" object2.Field3 = "2"
object3.Field1 = "a" object3.Field2 = "C" object3.Field3 = "3"
listB现在有两个对象object4和object6。
object4.Field1 = "a" object4.Field2 = "A" object4.Field3 = "1"
object6.Field1 = "a" object6.Field2 = "D" object6.Field3 = "3"
我几个小时都在摸不着头脑,但无济于事。我不能做一个foreach列表列表查看所有其他列表,因为它会导致性能问题(我可能有1000000个列表列表)。
有想法的人吗?
答案 0 :(得分:0)
为什么它必须是LINQ?一个简单的迭代器块很好地解决了这个问题。
以下代码假设您已在对象中覆盖Equals
和GetHashCode
,以检查3个字段是否相等。如果无法做到这一点,请改用自定义相等比较器(在HashSet构造函数中传递)
static IEnumerable<List<T>> GetFilteredList<T>(IEnumerable<List<T>> input)
{
var found = new HashSet<T>();
foreach (var list in input)
{
var returnList = new List<T>(list.Capacity);
foreach (var item in list)
{
// the first item is always added
// any other items are only added if they were
// never encountered before
if (list.Count == 0 || !found.Contains(item))
{
found.Add(item);
returnList.Add(item);
}
}
yield return returnList;
}
}
如果您坚持使用IEnumerable<IEnumerable<T>>
作为返回值,另一种只扫描输入一次的方法可能是这样的(不创建中间列表):
static IEnumerable<IEnumerable<T>> GetFilteredList<T>(IEnumerable<List<T>> input)
{
var encounteredElements = new HashSet<T>();
foreach (var list in input)
{
yield return Process(list, encounteredElements);
}
}
static IEnumerable<T> Process<T>(IEnumerable<T> input,
HashSet<T> encounteredElements)
{
bool first = true;
foreach (var item in input)
{
if (first) yield return item;
if (!encounteredElements.Contains(item))
{
yield return item;
}
encounteredElements.Add(item);
first = false;
}
}