Проверьте, все ли элементы коллекции имеют одинаковое значение - PullRequest
10 голосов
/ 10 сентября 2010

метод расширения для коллекции с именем MeasurementCollection проверяет, имеет ли свойство Template.Frequency (Enum) каждого элемента одинаковое значение.

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

    }

edit информация о базовых классах

    MeasurementCollection : ICollection<IMeasurement>

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

Это правильный подход или в Linq уже есть более простое решение?Этот метод будет интенсивно использоваться в приложении.

У вас есть советы, чтобы взять меня обратно к чертежной доске?

Ответы [ 7 ]

8 голосов
/ 10 сентября 2010

Вы можете просто найти первое значение и проверить, отличаются ли ЛЮБЫЕ другие, это позволит избежать необходимости оценивать всю коллекцию (если только одно другое значение не является последним)

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

}
8 голосов
/ 10 сентября 2010

Редактировать: чтобы решить проблемы Тимви с 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;
        }
    }
}
4 голосов
/ 10 сентября 2010

Первый из общих советов linq.Если вы просто хотите узнать, есть ли в коллекции ровно один, используйте Single () или SingleOrDefault ().Счетчик потенциально может выполнить итерацию всей коллекции, что больше, чем вам нужно, поскольку вы можете выручить, если их две.

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 голосов
/ 11 сентября 2010

Я получил немного вдохновения и подумал о решении, ориентируясь только на скорость. Это действительно не так хорошо читается (что я обычно предпочитаю), но характеристики, когда речь идет о скорости, должны быть довольно хорошими.

В худшем случае то же самое для большинства других реализаций 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 рекурсию.

2 голосов
/ 10 сентября 2010

Это будет быстрее, как это:

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 на частоте шаблона первого элемента, которая отличается, в то время как в вашем коде алгоритм пропускает всю коллекцию.

0 голосов
/ 21 апреля 2017

Я бы предложил следующее решение:

private static bool IsSameCollections(ICollection<> collection1, ICollection<> collection2)
        {
          return collection1.Count == collection2.Count &&
     (collection1.Intersect(collection2).Count() == collection1.Count);
        }
0 голосов
/ 22 января 2015

Я сделал это следующим образом:

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

Это раскрывающийся список со списком доступных статусов.Форма редактирует несколько активов.В раскрывающемся списке необходимо знать, имеют ли все активы одинаковое значение или нет.Мое же расширение делает это.

...