Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if all items in a Collection have the same value

An extension method on a collection named MeasurementCollection checks if the property Template.Frequency (Enum) of each item has the same value.

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

edit info about underlying classes

MeasurementCollection : ICollection<IMeasurement>

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

Is this a correct approach or is there an easier solution already in Linq? This method will be used intense in the application.

Have you got tips to take with me, back to the drawing board?

like image 256
Caspar Kleijne Avatar asked Sep 10 '10 19:09

Caspar Kleijne


3 Answers

You could just find the first value and check if ANY others are different, this will avoid having to eval the whole collection (unless the single different value is the last one)

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

}
like image 144
Christoph Avatar answered Oct 25 '22 23:10

Christoph


Edit: to address Timwi's concerns about 3 enumerators:

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

Which still uses 2 enumerators. Not an issue for the average List<>, but for a DB query it might pay to use the less readable:

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;
        }
    }
}
like image 34
Henk Holterman Avatar answered Oct 25 '22 23:10

Henk Holterman


First of a general linq advise. If you just what to know if there's exactly one in a collection use Single() or SingleOrDefault(). Count will potentially iterate the entire collection which is more than you need since you can bail out if there's two.

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));
        }
like image 41
Rune FS Avatar answered Oct 26 '22 00:10

Rune FS