检查集合中的所有项目是否具有相同的值

时间:2010-09-10 19:14:33

标签: c# linq arrays extension-methods

名为MeasurementCollection的集合上的扩展方法检查每个项目的属性Template.Frequency(Enum)是否具有相同的值。

    public static bool IsQuantized(this MeasurementCollection items)
    {
        return  (from i in items 
                 select i.Template.Frequency)
                .Distinct()
                .Count()==1;

    }

修改 有关基础类的信息

    MeasurementCollection : ICollection<IMeasurement>

    IMeasurement 
    {
    IMeasurementTemplate Template { get; }        
    ......
    }

这是一种正确的方法还是已经在Linq中有一个更简单的解决方案? 这种方法将在应用中得到充分利用。

你有提示要带我回到绘图板吗?

7 个答案:

答案 0 :(得分:8)

编辑:解决Timwi对3名调查员的担忧:

bool same = <your default> ;
var first = items.FirstOrDefault();
if (first != null)  // assuming it's a class
{
   same = items.Skip(1).All(i => i.Template.Frequency == first.Template.Frequency); 
}

仍然使用2个枚举器。平均List<>不是问题,但对于数据库查询,使用较不可读的内容可能会付出代价:

bool same = <your default> ;
Item first = null;

foreach(var item in items)
{
    if (first == null)
    {
        first = item;
        same = true;
    }
    else
    {
        if (item.Template.Frequency != first.Template.Frequency)
        {
           same = false;
           break;
        }
    }
}

答案 1 :(得分:8)

你可以找到第一个值并检查是否有其他值不同,这将避免必须评估整个集合(除非单个不同的值是最后一个)

public static bool IsQuantized(this MeasurementCollection items)
{
    if(!items.Any())
        return false; //or true depending on your use case

    //might want to check that Template is not null, a bit a violation of level of demeter, but just an example
    var firstProp = item.First().Template.Frequency;

    return !items.Any(x=> x.Template.Frequency != firstProp);

}

答案 2 :(得分:4)

一般的linq建议。如果您只知道集合中是否只有一个使用Single()或SingleOrDefault()。 Count会潜在地迭代整个集合,这超出了你的需要,因为如果有两个你可以拯救。

public static bool IsQuantized(this MeasurementCollection items)
        {
            var first = items.FirstOrDefault();
            return first != null && items.Skip(1).All(i => first.Template.Frequency == i.Template.Frequency));
        }

答案 3 :(得分:3)

我得到了一点灵感,想到了一个只考虑速度的解决方案。这真的不是那么可读(我通常更喜欢),但速度的特性应该非常好。

对于大多数其他实现O(n)来说,更糟糕的情况是相同的,但它极不可能,因为它要求所有前半部分元素都是等于后半部分一切都相等但不等于上半年的价值。 并且需要与线性搜索相同数量的比较。 在大多数其他情况下,随机位置的第一个奇数,这将需要一半的线性比较。 在值成对的情况下。所以item [0] == item [1] item [2] == item [3] item [0]!= item [2](和类似)那么线性搜索会更快。 通常,无论是随机数据还是少数奇数,这应该比线性搜索更快

public static bool AllSame<T>(this IEnumerable<T> source,
                              IEqualityComparer<T> comparer = null)
        {
            if (source == null)
                throw new ArgumentNullException("source cannot be null.", "source");

            if (comparer == null)
                comparer = EqualityComparer<T>.Default;
            var enumerator = source.GetEnumerator();

            return source.Zip(comparer);
        }

        private static bool Zip<T>(this IEnumerable<T> sequence, IEqualityComparer<T> comparer)
        {
            var result = new List<T>();
            var enumerator = sequence.GetEnumerator();
            while (enumerator.MoveNext())
            {
                var first = enumerator.Current;
                result.Add(enumerator.Current);
                if (enumerator.MoveNext())
                {
                    if (!comparer.Equals(first, enumerator.Current))
                    {
                       return false;
                    }
                }
                else
                {
                    break;
                }
            }
            return result.Count == 1 ? true : result.Zip(comparer);
        }

没有尾调用优化这会使用额外的内存(最坏的情况是内存量接近原始源使用的内存量)。调用堆栈不应该深入,因为没有IEnumerable具体实现(至少我知道)可以包含多于int.MaxValue元素。这将需要最多31次递归。

答案 4 :(得分:2)

这样会更快:

public static bool IsQuantized(this MeasurementCollection items)
{
    if(items == null || items.Count == 0)
       return true;

    var valueToCompare = items.First().Template.Frequency;

    return items.All(i => i.Template.Frequency == valueToCompare);
}

它将在第一个项目的模板频率上返回false,而在您的代码中,算法会传递整个集合。

答案 5 :(得分:0)

我已经这样做了:

public static bool Same<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
    {
        var val = source.Select(keySelector).FirstOrDefault();

        return source.Select(keySelector).All(a => Object.Equals(a, val));
    }

使用:

ddlStatus.AppendDataBoundItems = true;
ddlStatus.Items.Add(new ListItem("<Mixed>", "-1"));
ddlStatus.DataSource = ctx.Status.OrderBy(s => s.AssetStatus).ToList();
ddlStatus.DataTextField = "AssetStatus";
ddlStatus.DataValueField = "id";
ddlStatus.SelectedValue = Assets.Same(a => a.AssetStatusID) ? Assets.FirstOrDefault().AssetStatusID.ToString() : "-1";
ddlStatus.DataBind();

这是一个下拉框,其中包含可用状态列表。表单编辑多个资产。下拉列表需要知道资产是否都具有相同的值。我的相同扩展名就是这样做的。

答案 6 :(得分:0)

我建议遵循以下解决方案:

private static bool IsSameCollections(ICollection<> collection1, ICollection<> collection2)
        {
          return collection1.Count == collection2.Count &&
     (collection1.Intersect(collection2).Count() == collection1.Count);
        }
相关问题