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

C# 检查集合中的所有项是否具有相同的值,c#,linq,arrays,extension-methods,C#,Linq,Arrays,Extension Methods,名为MeasurementCollection的集合上的扩展方法检查每个项的属性Template.Frequency(枚举)是否具有相同的值 public static bool IsQuantized(this MeasurementCollection items) { return (from i in items select i.Template.Frequency) .Distinct() .Cou

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

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; }        
    ......
}
measurentcollection:ICollection
I测量
{
IMeasurementTemplate模板{get;}
......
}
这是一种正确的方法还是Linq中已经有了一种更简单的解决方案? 此方法将在应用中使用


回到绘图板上,你有什么建议要带上吗?

编辑:为了解决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); 
}
bool same=;
var first=items.FirstOrDefault();
if(first!=null)//假设它是一个类
{
same=items.Skip(1).All(i=>i.Template.Frequency==first.Template.Frequency);
}
它仍然使用2个枚举数。对于平均
列表
,这不是一个问题,但是对于DB查询,使用可读性较差的:

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;
        }
    }
}
bool same=;
第一项=空;
foreach(项目中的var项目)
{
if(first==null)
{
第一个=项目;
相同=正确;
}
其他的
{
if(item.Template.Frequency!=first.Template.Frequency)
{
相同=错误;
打破
}
}
}

这样会更快:

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,而在您的代码中,算法将传递整个集合。

常规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));
        }

您只需找到第一个值并检查其他值是否不同,这将避免对整个集合求值(除非单个不同的值是最后一个)


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

对于大多数其他实现O(n)来说,更糟糕的情况是相同的,但这不太可能,因为它要求所有元素的前半部分都相等,而后半部分都相等,但不等于前半部分的值。 并且需要与线性搜索相同数量的比较。 在大多数其他情况下,如果第一个奇数位于随机位置,则需要进行的比较数量为线性比较数量的一半。 在值成对的情况下。因此,项目[0]==项目[1]和项目[2]==项目[3]和项目[0]!=第[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);
        }
公共静态bool AllSame(此IEnumerable源代码,
IEqualityComparer比较器=空)
{
if(source==null)
抛出新ArgumentNullException(“源不能为null。”,“源”);
if(比较器==null)
comparer=EqualityComparer.Default;
var枚举器=source.GetEnumerator();
返回source.Zip(comparer);
}
私有静态bool-Zip(此IEnumerable序列,IEqualityComparer比较器)
{
var result=新列表();
var枚举器=sequence.GetEnumerator();
while(枚举数.MoveNext())
{
var first=枚举数。当前值;
结果.Add(枚举数.Current);
if(枚举数.MoveNext())
{
如果(!comparer.Equals(first,enumerator.Current))
{
返回false;
}
}
其他的
{
打破
}
}
返回result.Count==1?true:result.Zip(比较器);
}
如果没有尾调用优化,这将使用额外的内存(最坏的情况是内存量接近原始源所使用的内存量)。调用堆栈不应该深入,因为没有IEnumerable具体实现(至少我知道)可以容纳超过int.MaxValue元素。这将需要最多31个递归。

我是这样做的:

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));
    }
public static bool Same(此IEnumerable源代码,Func keySelector)
{
var val=source.Select(keySelector.FirstOrDefault();
返回source.Select(keySelector).All(a=>Object.Equals(a,val));
}
使用:

ddlStatus.AppendDataBoundItems=true;
ddlStatus.Items.Add(新列表项(“,”-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();

这是一个下拉框,包含可用状态的列表。该表单编辑多个资源。下拉列表需要知道所有资产是否具有相同的价值。我的同一个分机可以做到这一点。

我建议以下解决方案:

private static bool IsSameCollections(ICollection<> collection1, ICollection<> collection2)
        {
          return collection1.Count == collection2.Count &&
     (collection1.Intersect(collection2).Count() == collection1.Count);
        }
私有静态bool IsSameCollections(ICollection collection1、ICollection collection2)
{
return collection1.Count==collection2.Count&&
(collection1.Intersect(collection2.Count()==collection1.Count);
}

您的要求是什么可读性重要吗?速度重要吗?通常的情况是什么。它们是相同的还是不同的?根据您在这个问题上添加的#arrays标记,我们可以假设您的MeasurementCollection对象存储为数组或ArrayList吗?我们能否从MeasurementCollection中获得
.Count
,而不产生太多开销?哪个答案是正确的
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();
private static bool IsSameCollections(ICollection<> collection1, ICollection<> collection2)
        {
          return collection1.Count == collection2.Count &&
     (collection1.Intersect(collection2).Count() == collection1.Count);
        }