10

LINQで、リスト内のすべての数値が単調に増加しているかどうかを確認する方法があるかどうかに興味がありますか?

List<double> list1 = new List<double>() { 1, 2, 3, 4 };
Debug.Assert(list1.IsIncreasingMonotonically() == true);

List<double> list2 = new List<double>() { 1, 2, 100, -5 };
Debug.Assert(list2.IsIncreasingMonotonically() == false);

私が尋ねる理由は、リスト内の要素を前の要素と比較する手法を知りたいということです。これは、LINQを使用しているときに理解できなかったことです。

C#で完成したサンプルクラス

以下からの公式の回答によると、これ@Servyが私が現在使用している完全なクラスです。プロジェクトに拡張メソッドを追加して、リストが単調に増加/減少しているか、厳密に単調に増加しているかを確認します。関数型プログラミングのスタイルに慣れようとしていますが、これは学ぶのに良い方法です。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyHelper
{
    /// <summary>
    /// Classes to check if a list is increasing or decreasing monotonically. See:
    /// http://stackoverflow.com/questions/14815356/is-it-possible-to-use-linq-to-check-if-all-numbers-in-a-list-are-increasing-mono#14815511
    /// Note the difference between strictly monotonic and monotonic, see:
    /// http://en.wikipedia.org/wiki/Monotonic_function
    /// </summary>
    public static class IsMonotonic
    {
        /// <summary>
        /// Returns true if the elements in the are increasing monotonically.
        /// </summary>
        /// <typeparam name="T">Type of elements in the list.</typeparam>
        /// <param name="list">List we are interested in.</param>
        /// <returns>True if all of the the elements in the list are increasing monotonically.</returns>
        public static bool IsIncreasingMonotonically<T>(this List<T> list) where T : IComparable
        {
            return list.Zip(list.Skip(1), (a, b) => a.CompareTo(b) <= 0).All(b => b);
        }

        /// <summary>
        /// Returns true if the elements in the are increasing strictly monotonically.
        /// </summary>
        /// <typeparam name="T">Type of elements in the list.</typeparam>
        /// <param name="list">List we are interested in.</param>
        /// <returns>True if all of the the elements in the list are increasing monotonically.</returns>
        public static bool IsIncreasingStrictlyMonotonically<T>(this List<T> list) where T : IComparable
        {
            return list.Zip(list.Skip(1), (a, b) => a.CompareTo(b) < 0).All(b => b);
        }

        /// <summary>
        /// Returns true if the elements in the are decreasing monotonically.
        /// </summary>
        /// <typeparam name="T">Type of elements in the list.</typeparam>
        /// <param name="list">List we are interested in.</param>
        /// <returns>True if all of the the elements in the list are decreasing monotonically.</returns>
        public static bool IsDecreasingMonotonically<T>(this List<T> list) where T : IComparable
        {
            return list.Zip(list.Skip(1), (a, b) => a.CompareTo(b) >= 0).All(b => b);
        }

        /// <summary>
        /// Returns true if the elements in the are decreasing strictly monotonically.
        /// </summary>
        /// <typeparam name="T">Type of elements in the list.</typeparam>
        /// <param name="list">List we are interested in.</param>
        /// <returns>True if all of the the elements in the list are decreasing strictly monotonically.</returns>
        public static bool IsDecreasingStrictlyMonotonically<T>(this List<T> list) where T : IComparable
        {
            return list.Zip(list.Skip(1), (a, b) => a.CompareTo(b) > 0).All(b => b);
        }

        /// <summary>
        /// Returns true if the elements in the are increasing monotonically.
        /// </summary>
        /// <typeparam name="T">Type of elements in the list.</typeparam>
        /// <param name="list">List we are interested in.</param>
        /// <returns>True if all of the the elements in the list are increasing monotonically.</returns>
        public static bool IsIncreasingMonotonicallyBy<T>(this List<T> list, Func<T> x) where T : IComparable
        {
            return list.Zip(list.Skip(1), (a, b) => a.CompareTo(b) <= 0).All(b => b);
        }

        public static void UnitTest()
        {
            {
                List<double> list = new List<double>() { 1, 2, 3, 4 };
                Debug.Assert(list.IsIncreasingMonotonically<double>() == true);
                Debug.Assert(list.IsIncreasingStrictlyMonotonically<double>() == true);
                Debug.Assert(list.IsDecreasingMonotonically<double>() == false);
                Debug.Assert(list.IsDecreasingStrictlyMonotonically<double>() == false);
            }

            {
                List<double> list = new List<double>() { 1, 2, 100, -5 };
                Debug.Assert(list.IsIncreasingMonotonically() == false);
                Debug.Assert(list.IsIncreasingStrictlyMonotonically() == false);
                Debug.Assert(list.IsDecreasingMonotonically() == false);
                Debug.Assert(list.IsDecreasingStrictlyMonotonically() == false);
            }

            {
                List<double> list = new List<double>() {1, 1, 2, 2, 3, 3, 4, 4};
                Debug.Assert(list.IsIncreasingMonotonically() == true);
                Debug.Assert(list.IsIncreasingStrictlyMonotonically<double>() == false);
                Debug.Assert(list.IsDecreasingMonotonically() == false);
                Debug.Assert(list.IsDecreasingStrictlyMonotonically() == false);
            }

            {
                List<double> list = new List<double>() { 4, 3, 2, 1 };
                Debug.Assert(list.IsIncreasingMonotonically() == false);
                Debug.Assert(list.IsIncreasingStrictlyMonotonically<double>() == false);
                Debug.Assert(list.IsDecreasingMonotonically() == true);
                Debug.Assert(list.IsDecreasingStrictlyMonotonically() == true);
            }

            {
                List<double> list = new List<double>() { 4, 4, 3, 3, 2, 2, 1, 1 };
                Debug.Assert(list.IsIncreasingMonotonically() == false);
                Debug.Assert(list.IsIncreasingStrictlyMonotonically<double>() == false);
                Debug.Assert(list.IsDecreasingMonotonically() == true);
                Debug.Assert(list.IsDecreasingStrictlyMonotonically() == false);
            }
        }
    }
}
4

8 に答える 8

12
public static bool IsIncreasingMontonically<T>(List<T> list) 
    where T : IComparable
{
    return list.Zip(list.Skip(1), (a, b) => a.CompareTo(b) <= 0)
        .All(b => b);
}

これにより、シーケンスが 2 回繰り返されることに注意してください。aListの場合はまったく問題ありませんが、IEnumerableorの場合は問題になる可能性があるため、 に変更するIQueryable前に注意してください。List<T>IEnumerable<T>

于 2013-02-11T15:41:31.537 に答える
6

を使用してリストを注文OrderBy()し、元のリストと比較してみませんか?それらが同じである場合、それはあなたの答えを疑似的に話すでしょう:

var increasing = orignalList.OrderBy(m=>m.value1).ToList();
var decreasing = orignalList.OrderByDescending(m=>m.value1).ToList();

var mono = (originalList == increasing || originalList == decreasing)
于 2013-02-11T15:39:23.120 に答える
4

メソッドを使用してEnumerable.Aggregate:

list1.Aggregate((a, i) => a > i ? double.MaxValue : i) != double.MaxValue;
于 2013-02-11T16:32:31.407 に答える
1

指定された IEnumerable を 1 回だけ列挙する、次のような実装を検討してください。列挙には副作用がある可能性があり、呼び出し元は通常、可能であれば単一のパススルーを期待します。

public static bool IsIncreasingMonotonically<T>(
    this IEnumerable<T> _this)
    where T : IComparable<T>
{
    using (var e = _this.GetEnumerator())
    {
        if (!e.MoveNext())
            return true;
        T prev = e.Current;
        while (e.MoveNext())
        {
            if (prev.CompareTo(e.Current) > 0)
                return false;
            prev = e.Current;
        }
        return true;
    }
}
于 2013-02-13T20:36:20.633 に答える
1
public static class EnumerableExtensions
{
    private static bool CompareAdjacentElements<TSource>(this IEnumerable<TSource> source,
        Func<TSource, TSource, bool> comparison)
    {
        using (var iterator = source.GetEnumerator())
        {
            if (!iterator.MoveNext())
                throw new ArgumentException("The input sequence is empty", "source");
            var previous = iterator.Current;
            while (iterator.MoveNext())
            {
                var next = iterator.Current;
                if (comparison(previous, next)) return false;
                previous = next;
            }
            return true;
        }
    }

    public static bool IsSorted<TSource>(this IEnumerable<TSource> source)
        where TSource : IComparable<TSource>
    {
        return CompareAdjacentElements(source, (previous, next) => previous.CompareTo(next) > 0);
    }

    public static bool IsSorted<TSource>(this IEnumerable<TSource> source, Comparison<TSource> comparison)
    {
        return CompareAdjacentElements(source, (previous, next) => comparison(previous, next) > 0);
    }

    public static bool IsStrictSorted<TSource>(this IEnumerable<TSource> source)
        where TSource : IComparable<TSource>
    {
        return CompareAdjacentElements(source, (previous, next) => previous.CompareTo(next) >= 0);
    }

    public static bool IsStrictSorted<TSource>(this IEnumerable<TSource> source, Comparison<TSource> comparison)
    {
        return CompareAdjacentElements(source, (previous, next) => comparison(previous, next) >= 0);
    }
}
于 2014-02-14T07:52:10.633 に答える
1

リストが常にインデックスからインデックスへと増加しているかどうかを確認したい場合:

IEnumerable<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 10 };
bool allIncreasing = !list
    .Where((i, index) => index > 0 && list.ElementAt(index - 1) >= i)
    .Any();

デモ

しかし、私の意見では、この場合は単純なループの方が読みやすいでしょう。

于 2013-02-11T15:43:47.920 に答える