Подтвердить что ты не робот

Проверьте, имеют ли все элементы в коллекции одинаковое значение

Метод расширения в коллекции с именем 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 уже есть более простое решение? Этот метод будет интенсивно использоваться в приложении.

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

4b9b3361

Ответ 1

Изменить: для обращения к Timwi относится к трем перечислениям:

bool same = <your default> ;
var first = items.FirstOrDefault();
if (first != null)  // assuming it 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;
        }
    }
}

Ответ 2

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

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

}

Ответ 3

Сначала из общей рекомендации 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));
        }

Ответ 4

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

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

Ответ 5

Это будет быстрее:

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

Ответ 6

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

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

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

Ответ 7

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

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