如何确定一个值是否在范围列表内?

时间:2018-08-06 13:10:26

标签: c# numbers integer

我有一个输入类型,其中包含最小值和最大值的列表。我需要做的是验证列表,以确保最小/最大值之间没有重叠。 DTO看起来与此类似

public class FeeDTO
{
    /// <summary>
    /// Gets or sets the fees.
    /// </summary>
    /// <value>
    /// The fees.
    /// </value>
    public List<IndividualFee> Fees { get; set; }
}

public class IndividualFee
{

    /// <summary>
    /// Gets or sets the minimum value.
    /// </summary>
    /// <value>
    /// The minimum value.
    /// </value>
    public Int32 MinValue { get; set; }

    /// <summary>
    /// Gets or sets the maximum value.
    /// </summary>
    /// <value>
    /// The maximum value.
    /// </value>
    public Int32 MaxValue { get; set; }
}

例如,由于所有范围都是互斥的,因此此输入就可以了:

  • 范围1:最小值= 0最大值= 100
  • 范围2:最小值= 101最大值= 200
  • 范围3:最小值= 201最大值= 300

但是,在下面的示例中,范围3分钟的值落在范围2之内

  • 范围1:最小值= 0最大值= 100
  • 范围2:最小值= 101最大值= 200
  • 范围3:最小值= 199最大值= 300

我的问题是,用于检测值之间的重叠的最佳方法是什么?

3 个答案:

答案 0 :(得分:0)

我认为解决这个问题的最明显方法是创建一个遍历每个最大值并将其与每个最小值进行比较的foreach。我们也可以使用LINQ使代码更加紧凑,我敢肯定可能会有更高效的算法,但这是我能想到的:

foreach(IndividualFee fee in Fees){
    if(Fees.FirstOrDefault(f => f.MaxValue > fee.MinValue) != null){
        //Code for if the ranges are overlapping
    }
}

答案 1 :(得分:0)

例如,您可以创建一个自定义集合类型,每当添加新项目时,该集合类型就会根据您的逻辑验证数据,例如:

public class FeeList : ICollection<IndividualFee>
{
    private readonly List<IndividualFee> _list = new List<IndividualFee>();

    public int Count => _list.Count;

    public bool IsReadOnly => false;

    public void Add(IndividualFee item)
    {
        if (item == null)
            throw new ArgumentNullException(nameof(item));
        if (item.MaxValue < item.MinValue)
            throw new ArgumentException("Overlaps", nameof(item));
        if (_list.Count > 0 && item.MinValue < _list[_list.Count - 1].MaxValue)
            throw new ArgumentException("Overlaps", nameof(item));
    }

    public void Clear() => _list.Clear();

    public bool Contains(IndividualFee item) => _list.Contains(item);

    public void CopyTo(IndividualFee[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex);

    public IEnumerator<IndividualFee> GetEnumerator() => _list.GetEnumerator();

    public bool Remove(IndividualFee item) => _list.Remove(item);

    IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator();
}

然后您在DTO类中使用此自定义类型,而不是使用List<T>

public class FeeDTO
{
    public FeeList Fees { get; set; }
}

这应该确保您不会在没有引发异常的情况下将任何无效数据添加到FeeDTO对象。

如果您不想在验证失败时抛出异常,则可以将IsValid属性添加到FeeList并适当地设置该属性。

答案 2 :(得分:0)

简单Fiddle with tests here

public static bool IsOverlap(IEnumerable<IndividualFee> fees)
{
    var limit = int.MinValue;
    foreach (var fee in fees.OrderBy(f => f.MinValue))
    {
        if (fee.MinValue <= limit)
        {
            return true;
        }

        limit = fee.MinValue;

        if (fee.MaxValue <= limit)
        {
            return true;
        }

        limit = fee.MaxValue;

    }

    return false;
}