2

我在某个区间内定义了三种数值范围,例如:
1.计数范围(指定区间内的任何值)
2.周期性序列(指定序列开始、步数和步数)
3.一组精确值(如1、3、7 等)

我需要联合/相交它们(从 2 到 N 的不同类型)并获得优化的结果。显然,上面的交集将返回上面一种类型的结果,将它们联合起来将产生上面 1 到 M 个类型的范围。
示例 1:
第一个范围定义为从 5 到 11 的连续范围,第二个是从 2 到 18 的周期性序列,步骤 2(因此为 8 个步骤)。
Intersection 将返回一个从 6 到 10 的周期序列,步骤
2。Union 将返回三个结果:一个周期序列从 2 到 4,步骤 2,连续范围从 5 到 11,周期序列从 12 到 18,步骤 2。
示例 2:
第 1 个范围定义为第 2 步的周期序列 0 到 10,第 2 个范围是第 2 步的从 1 到 7 的周期序列(因此,3 步)。
Intersection 将返回 null,因为它们不相交。
Union 将返回两个结果:一个从 1 到 8 的周期性序列,第 1 步(注意:优化结果)和一个精确值 10。
希望我没有犯错 :)
好吧,这些序列上的这些操作不应该太复杂并且我希望这里有一个图书馆。请提供任何建议(将在 C#.NET 中使用)。
谢谢!

更新
回答“我认为我如何使用图书馆”。以上三种类型都可以在编程语言中轻松定义为:
1. Contionous: { decimal Start; 小数结束;} 其中 Start 是范围的开始,End 是结束
2. Periodical: { decimal Start; 小数步长;整数计数;} 其中 Start 是序列的开头, Step 是增量, Count 是步数
3. 精确数字集:{ decimal[] Values; 其中 Values 是一些小数的数组。

当我对上面列出的任何类型的任何两个范围进行交集时,我肯定会得到其中一种类型的结果,例如“连续”和“定期”范围的交集将导致“定期”、“连续”。和“精确的集合”将导致精确的集合,“续”。并且“精确”也将返回精确值。相同类型的交集将返回输入类型的结果。
2 个范围的联合有点复杂,但无论如何也会返回在上述类型中定义的 2 到 3 个范围。
拥有交集/联合功能,我将始终能够在 2 到 N 范围内运行它,并将在输入类型术语中得到结果。

4

2 回答 2

2

首先,遵循之前的其他答案:我不相信有一个标准库:它看起来非常像一个特例。

其次,问题/要求表述不够清楚。我将按照问题介绍,将 3 种不同的类型称为“set”、“periodic”、“continuous”。

考虑两个集合,{1,4,5,6} 和 {4,5,6,8}。它们的交点是 {4,5,6}。我们是否必须将其标记为“周期性”,因为该描述适合这种情况,或者因为它是集合的交集而标记为“集合”?

由此,更一般地,我们是否需要将“set”标签更改为“periodic”,只要它的内容是周期性的?毕竟,“周期”是“集合”的特例。

同样,考虑“周期性”{4,6,8} 和集合 {10,15,16} 的并集。我们是否必须将结果定义为一个周期性的 {4,6,8,10} 加上一个周期性的{15,16} 或者更确切地说是一个包含所有值的集合,或者另一个品种?

那么退化的情况呢:{3} 是“集合”、“周期性”,还是“连续”?“连续”{1-4} 和“集合”{4,7,8} 的交集是什么类型?以及连续{1-4}和连续{4-7}的交集?

等等:必须清楚任何结果 - 来自联合和/或交集 - 必须如何标记/描述,例如 - 两个离散类型(非连续)的交集或联合是否始终是一种类型(通常一个集合,可能是一个周期性的),或者更确切地说总是一系列周期性,或者......

第三,假设上述问题已经解决,我相信您可以按照以下准则来实现:

  • 只考虑两种“类型”,即“连续”和“集合”。“周期”只是“集合”的一种特殊形式,在任何时候,如果合适的话,我们可以将“集合”标记为“周期”。

  • 定义一个公共基类,并使用适当的派生(重载)方法来进行联合、交集和您可能需要的任何东西,以生成 - 例如 - 作为结果的列表(baseType)。

逐个案例的实现基本上非常简单——假设我的介绍性问题已经得到解答。无论最初的问题在哪里显得有些“困难”,这只是因为问题和规范还没有很好地定义。

于 2012-10-04T14:43:48.997 回答
0

这一切听起来都很定制——所以我认为你不会找到一个可以立即完成所有这些工作的库——但那里没有什么太难的地方。

我会让你开始的。对于第一个示例来说工作正常,但该方法Range.ConstructAppropriate需要特别复杂才能返回“从 2 到 4 的周期性序列,第 2 步,从 5 到 11 的连续范围,以及从 12 到 18 的周期性序列,第 2 步”由{ 5, 6, 7, 8, 9, 10, 11, 2, 4, 12, 14, 16, 18 }示例 1 中的两个集合并集得到的集合。

另外(在麻烦连接所有代码之后)我从评论中注意到您需要非整数。这使事情复杂化。我想你可以想出一种创造性的方式来应用这种模式。

class Program
{
    static void Main(string[] args)
    {
        // Example 1:
        // 1st range is defined as continous range from 5 to 11 and 2nd is periodical sequence from 2 to 18 with step 2 (thus, 8 steps).
        // Intersection will return a periodic sequence from 6 to 10 with step 2.example 1

        ContinuousRange ex1_r1 = new ContinuousRange(5, 11);
        PeriodicRange ex1_r2 = new PeriodicRange(2, 2, 8);

        IEnumerable<int> ex1_intersection = ex1_r1.Values.Intersect(ex1_r2.Values);
        IList<Range> ex1_intersection_results = Range.ConstructAppropriate(ex1_intersection);
    }
}

abstract class Range
{
    public abstract IEnumerable<int> Values { get; }

    public static IList<Range> ConstructAppropriate(IEnumerable<int> values)
    {
        var results = new List<Range>();

        results.Add(ContinuousRange.ConstructFrom(values));
        results.Add(PeriodicRange.ConstructFrom(values));

        if (!results.Any(r => r != null))
            results.Add(Points.ConstructFrom(values));

        return results.Where(r => r != null).ToList();
    }
}

class ContinuousRange : Range
{
    int start, endInclusive;

    public ContinuousRange(int start, int endInclusive)
    {
        this.start = start;
        this.endInclusive = endInclusive;
    }

    public override IEnumerable<int> Values
    {
        get
        {
            return Enumerable.Range(start, endInclusive - start + 1);
        }
    }

    internal static ContinuousRange ConstructFrom(IEnumerable<int> values)
    {
        int[] sorted = values.ToArray();
        if (sorted.Length <= 1)
            return null;

        for (int i = 1; i < sorted.Length; i++)
        {
            if (sorted[i] - sorted[i - 1] != 1)
                return null;
        }

        return new ContinuousRange(sorted.First(), sorted.Last());
    }
}

class PeriodicRange : Range
{
    int start, step, count;

    public PeriodicRange(int start, int step, int count)
    {
        this.start = start;
        this.step = step;
        this.count = count;
    }

    public override IEnumerable<int> Values
    {
        get
        {
            var nums = new List<int>();
            int i = start;
            int cur = 0;

            while (cur <= count)
            {
                nums.Add(i);
                i += step;
                cur++;
            }

            return nums;
        }
    }

    internal static Range ConstructFrom(IEnumerable<int> values)
    {
        // check the difference is the same between all values

        if (values.Count() < 2)
            return null;

        var sorted = values.OrderBy(a => a).ToArray();

        int step = sorted[1] - sorted[0];

        for (int i = 2; i < sorted.Length; i++)
        {
            if (step != sorted[i] - sorted[i - 1])
                return null;
        }

        return new PeriodicRange(sorted[0], step, sorted.Length - 1);
    }
}

class Points : Range
{
    int[] nums;

    public Points(params int[] nums)
    {
        this.nums = nums;
    }

    public override IEnumerable<int> Values
    {
        get { return nums; }
    }

    internal static Range ConstructFrom(IEnumerable<int> values)
    {
        return new Points(values.ToArray());
    }
}
于 2012-10-04T13:24:55.227 回答