C# 区分但忽略空/空

C# 区分但忽略空/空,c#,linq,morelinq,C#,Linq,Morelinq,我有一个电影列表,我需要将它们与另一个列表合并并复制 我正在使用Jon Skeet的DistinctBy(m=>m.SomeUniqueMovieProperty)来实现这一点,它工作正常。除此之外,我们很快发现,在某些情况下,10-20%的电影(在任一列表中)没有填写此属性,从而导致DistinctBy将它们折叠成一部幸运电影 这是一个问题,我们希望保留所有没有此属性值的电影。最初我想从每个收藏中提取这些电影,复制,然后再合并,有没有一个较短的解决方案 将DistinctBy()的结果与Whe

我有一个电影列表,我需要将它们与另一个列表合并并复制

我正在使用Jon Skeet的
DistinctBy(m=>m.SomeUniqueMovieProperty)
来实现这一点,它工作正常。除此之外,我们很快发现,在某些情况下,10-20%的电影(在任一列表中)没有填写此属性,从而导致
DistinctBy
将它们折叠成一部幸运电影


这是一个问题,我们希望保留所有没有此属性值的电影。最初我想从每个收藏中提取这些电影,复制,然后再合并,有没有一个较短的解决方案

DistinctBy()
的结果与
Where([null或empty])的结果连接起来。


DistinctBy()
的结果与
Where([null或empty])的结果连接起来。


如果要包含所有null,则需要将null属性替换为null时唯一的属性。假设属性是字符串,Guid将很好地完成此任务

.DistinctBy(m => m.SomeUniqueMovieProperty ?? Guid.NewGuid().ToString())
任何时候,当它遇到一个空值的属性时,它都会被一个随机的新guid值填充


如果您还希望不删除空标题,请将查询更改为

.DistinctBy(m => String.IsNullOrEmpty(m.SomeUniqueMovieProperty) ? Guid.NewGuid().ToString() : m.SomeUniqueMovieProperty)

另一个选项是通过使您自己的
表现出您想要的方式。这是一个经过调整的版本,仅当
shouldApplyFilter
返回true时才应用过滤器,为简洁起见,注释也被删除

static partial class MoreEnumerable
{
    public static IEnumerable<TSource> ConditionalDistinctBy<TSource, TKey>(this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector, Func<TKey, bool> shouldApplyFilter)
    {
        return source.ConditionalDistinctBy(keySelector, shouldApplyFilter, null);
    }

    public static IEnumerable<TSource> ConditionalDistinctBy<TSource, TKey>(this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector, Func<TKey, bool> shouldApplyFilter, IEqualityComparer<TKey> comparer)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (keySelector == null) throw new ArgumentNullException("keySelector");
        if (shouldApplyFilter == null) throw new ArgumentNullException("shouldApplyFilter");
        return ConditionalDistinctByImpl(source, keySelector, shouldApplyFilter, comparer);
    }

    private static IEnumerable<TSource> ConditionalDistinctByImpl<TSource, TKey>(IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector, Func<TKey, bool> shouldApplyFilter, IEqualityComparer<TKey> comparer)
    {
        var knownKeys = new HashSet<TKey>(comparer);
        foreach (var element in source)
        {
            var key = keySelector(element);
            if (shouldApplyFilter(key) && knownKeys.Add(key))
            {
                yield return element;
            }
        }
    }
}

如果要包含所有null,则需要将null属性替换为null时唯一的属性。假设属性是字符串,Guid将很好地完成此任务

.DistinctBy(m => m.SomeUniqueMovieProperty ?? Guid.NewGuid().ToString())
任何时候,当它遇到一个空值的属性时,它都会被一个随机的新guid值填充


如果您还希望不删除空标题,请将查询更改为

.DistinctBy(m => String.IsNullOrEmpty(m.SomeUniqueMovieProperty) ? Guid.NewGuid().ToString() : m.SomeUniqueMovieProperty)

另一个选项是通过
使您自己的
表现出您想要的方式。这是一个经过调整的版本,仅当
shouldApplyFilter
返回true时才应用过滤器,为简洁起见,注释也被删除

static partial class MoreEnumerable
{
    public static IEnumerable<TSource> ConditionalDistinctBy<TSource, TKey>(this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector, Func<TKey, bool> shouldApplyFilter)
    {
        return source.ConditionalDistinctBy(keySelector, shouldApplyFilter, null);
    }

    public static IEnumerable<TSource> ConditionalDistinctBy<TSource, TKey>(this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector, Func<TKey, bool> shouldApplyFilter, IEqualityComparer<TKey> comparer)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (keySelector == null) throw new ArgumentNullException("keySelector");
        if (shouldApplyFilter == null) throw new ArgumentNullException("shouldApplyFilter");
        return ConditionalDistinctByImpl(source, keySelector, shouldApplyFilter, comparer);
    }

    private static IEnumerable<TSource> ConditionalDistinctByImpl<TSource, TKey>(IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector, Func<TKey, bool> shouldApplyFilter, IEqualityComparer<TKey> comparer)
    {
        var knownKeys = new HashSet<TKey>(comparer);
        foreach (var element in source)
        {
            var key = keySelector(element);
            if (shouldApplyFilter(key) && knownKeys.Add(key))
            {
                yield return element;
            }
        }
    }
}

也许您可以在一个复合的独立键上过滤它们,如下所示

movies.DistinctBy(m => String.Format({0}{1}{...},m.prop1,m.prop2,[]));

也许您可以在一个复合的独立键上过滤它们,如下所示

movies.DistinctBy(m => String.Format({0}{1}{...},m.prop1,m.prop2,[]));

最后一种方法,这可能是过度的,你可以实现IEqualityComparer,并把逻辑放在那里,如果NULL被认为是唯一的。DistinctBy仅在这种情况下有一个重载

public class MovieComparer : IEqualityComparer<string>
{

    public bool Equals(string x, string y)
    {
        if (x == null || y == null)
        {
            return false;
        }

        return x == y;
    }

    public int GetHashCode(string obj)
    {
        if (obj == null)
        {
            return 0;
        }
        return obj.GetHashCode();
    }
}
public-class-MovieComparer:IEqualityComparer
{
公共布尔等于(字符串x、字符串y)
{
如果(x==null | | y==null)
{
返回false;
}
返回x==y;
}
public int GetHashCode(字符串obj)
{
if(obj==null)
{
返回0;
}
返回obj.GetHashCode();
}
}

最后一种方法,这可能是过多的,如果NULL被认为是唯一的,你可以实现IEqualityComparer并把逻辑放在那里。DistinctBy仅在这种情况下有一个重载

public class MovieComparer : IEqualityComparer<string>
{

    public bool Equals(string x, string y)
    {
        if (x == null || y == null)
        {
            return false;
        }

        return x == y;
    }

    public int GetHashCode(string obj)
    {
        if (obj == null)
        {
            return 0;
        }
        return obj.GetHashCode();
    }
}
public-class-MovieComparer:IEqualityComparer
{
公共布尔等于(字符串x、字符串y)
{
如果(x==null | | y==null)
{
返回false;
}
返回x==y;
}
public int GetHashCode(字符串obj)
{
if(obj==null)
{
返回0;
}
返回obj.GetHashCode();
}
}

假设
m
等于
/
GetHashCode
未被覆盖,如果
m.SomeUniqueMovieProperty
null
且您没有任何其他唯一键,则可以使用
m
本身作为唯一键

DistinctBy(m => (object) m.SomeUniqueMovieProperty ?? m)

假设
m
等于
/
GetHashCode
未被覆盖,如果
m.SomeUniqueMovieProperty
null
且您没有任何其他唯一键,则可以使用
m
本身作为唯一键

DistinctBy(m => (object) m.SomeUniqueMovieProperty ?? m)


我会听从你的选择。过滤掉那些将为null属性值的,在其上运行distinct by,然后将其与过滤后的合并。我会按照您的选择。过滤掉那些将为null属性值的值,在其上运行distinct by,然后将其与过滤后的值合并。您完全忽略了当SomeUniqueMovieProperty等于随机数的字符串表示形式时的情况;)如果该属性可以预测由
Guid.NewGuid()
生成的Guid,我认为它应该被过滤掉,这太危险了,它是心理的;)不是吹毛求疵,只是想提醒op在title@MrAnderson我认为标题可能会被干扰为“DistinctBy,但忽略null/empty,只包含所有内容”@MrAnderson,如果:)您完全忽略了某些UniqueMovieProperty等于随机数的字符串表示形式的情况;),我建议您远离gaming.stackexchange.com如果该属性可以预测由
Guid.NewGuid()
生成的Guid,我认为它应该被过滤掉,这太危险了,它是心理的;)不是吹毛求疵,只是想提醒op在title@MrAnderson我认为标题可能会被干扰为“DistinctBy,但忽略null/empty,只包含所有内容”@MrAnderson此外,我建议您远离gaming.stackexchange.com,如果:)+1个有趣的想法,不幸的是,该属性是唯一一个足以确定唯一性的可靠属性。如果你认为这是可靠的;)+我有一个有趣的想法,不幸的是,属性是唯一一个足以确定唯一性的可靠属性。如果你称之为可靠;)这个属性的值可能是空的,所以这个解决方案会占便宜。Scott的解决方案可以与什么一起使用?但可读性变差了+1到他的解决方案,也可能在另一种情况下工作此解决方案的一个缺点是它会导致对
allMovies
的多个枚举,我们可能会有空值