簡體   English   中英

檢查集合中的所有項目是否具有相同的值

[英]Check if all items in a Collection have the same value

名為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中有一個更簡單的解決方案? 該方法將在應用中得到廣泛應用。

你有提示帶我回到繪圖板嗎?

您可以找到第一個值並檢查是否有其他值不同,這將避免必須評估整個集合(除非單個不同的值是最后一個)

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 = items.First().Template.Frequency;

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

}

編輯:解決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;
        }
    }
}

一般的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),更糟糕的情況是相同的,但是它非常不可能,因為它將要求所有前半部分元素相等后半部分全部相等但不等於中的值上半場。 並且需要與線性搜索相同數量的比較。 在大多數其他情況下,隨機位置的第一個奇數,這將需要一半的線性比較。 在值成對的情況下。 所以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次遞歸。

它會更快這樣:

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,這是不同的,而在您的代碼中,算法會傳遞整個集合。

我這樣做了:

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();

這是一個下拉框,其中包含可用狀態列表。 表單編輯多個資產。 下拉列表需要知道資產是否都具有相同的值。 我的相同擴展名是這樣的。

我建議以下解決方案:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM