合并两个 IEnumerable<T>

44

我有两个IEnumerable<T>

其中一个用默认值填充。这个序列将始终包含最多的元素。 另一个根据一些参数进行填充,可能包含较少的元素。 如果第二个序列中不存在某个元素,则需要使用第一个序列中相应元素进行填充。

下面的代码可以完成任务,但我觉得效率不高,并且需要将 IEnumerable 转换为 IList 或使用临时列表。 Person 实现了 IEquatable 接口。

IEnumerable<Person> fallBack = Repository.GetPersons();
IList<Person> translated = Repository.GetPersons(language).ToList();

foreach (Person person in fallBack)
{
    if (!translated.Any(p=>p.equals(person)))
        translated.add(person);  
}

有什么建议吗?

3个回答

50
translated.Union(fallback)

或者(如果Person没有通过ID实现IEquatable<Person>)
translated.Union(fallback, PersonComparer.Instance)

PersonComparer 是什么:

public class PersonComparer : IEqualityComparer<Person>
{
    public static readonly PersonComparer Instance = new PersonComparer();

    // We don't need any more instances
    private PersonComparer() {}

    public int GetHashCode(Person p)
    {
        return p.id;
    }

    public bool Equals(Person p1, Person p2)
    {
        if (Object.ReferenceEquals(p1, p2))
        {
            return true;
        }
        if (Object.ReferenceEquals(p1, null) ||
            Object.ReferenceEquals(p2, null))
        {
            return false;
        }
        return p1.id == p2.id;
    }
}

只有在Person类正确实现了相等性时,这才能正常工作。根据OP的描述,我猜他们没有这样做。 - JaredPar
哈哈!Jon,你不能把它打包得更复杂一些吗?我又感到非常愚蠢 :P - Boris Callens
实际上他们确实有。楼主发布的内容也没有真正的代码。部分原因是为了简化我的问题,部分原因是因为我的老板害怕在公共区域放置代码 :s - Boris Callens
@Jared:我快到那里了 :) - Jon Skeet
2
实际上,我担心这似乎不是我想要的解决方案。这将给我一个包含两者所有元素的集合,并且它永远不会触发我的Equals(Person other)方法。我做错了什么还是我表达得不清楚? - Boris Callens

34

试一下这个。

public static IEnumerable<Person> SmartCombine(IEnumerable<Person> fallback, IEnumerable<Person> translated) {
  return translated.Concat(fallback.Where(p => !translated.Any(x => x.id.equals(p.id)));
}

4
这个方法很有效,但有一个需要注意的问题: http://programmaticallyspeaking.com/how-enumerableconcat-brought-down-a-production-server.html - Oliver
我会避免多次使用IEnumerable。因为在“底层”,它可能会重新连接到数据库或对每个枚举执行一些计算。或者,例如,只是无限的... - N. Kudryavtsev

0

使用Concat。在List<dynamic>类型的情况下,Union无法工作。


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