【问题标题】:How to return all ranges that are not included in any other range C# list如何返回不包含在任何其他范围 C# 列表中的所有范围
【发布时间】:2018-07-05 07:35:19
【问题描述】:

我有一个价值列表Tuple 如下:

List<(int, int)> values = new List<(int, int)>
{
  (12, 15),
  (18, 30),
  (18, 27),
  (27, 30)
};

现在我想删除这个列表中的对,它在更宽对的范围内。

例如:(18, 27)(27, 30)(18, 30) 的范围内。所以,我想删除它下面的那些对。

所以最终的输出一定是:

(12, 15)
(18, 30)

我正在考虑使用 LINQ 的 .RemoveAll() 方法删除这些对,但我不知道该怎么做。

任何帮助将不胜感激。

【问题讨论】:

  • 您能否解释一下:(18, 30) 同时包含 (18, 27) 和 (27, 30)
  • 为什么 (18, 30) 比 (27, 30) 大?
  • 如果(18, 30) 包含(27, 30)。它是否也包含(30, 27)
  • 那么为什么它会选择(0, 9)而不是更大范围的(10, 100)呢?您的规范中缺少一些细节。它是否应该检查哪个范围包含最多的子范围,并使用那个?您的规范的问题是未定义的术语biggest pair。如果有两个范围包含相同数量的子范围,它应该选择哪个?这两个中最大的?还是第一个?
  • 因此,更清楚地说明要求的方式是:Return all ranges that are not included in any other range

标签: c# arrays linq subset


【解决方案1】:

如果我理解正确,这将起到作用。它将列表的每个值与整个列表进行比较,直到找到另一个位于不完全相等范围内的元组。

List<(int, int)> values = new List<(int, int)>
{
    (12, 15),
    (18, 30),
    (18, 27),
    (27, 30)
};

values.RemoveAll(x => values.Any(y => x.CompareTo(y) != 0 && x.Item1 >= y.Item1 && x.Item2 <= y.Item2));

【讨论】:

  • 如果(30, 27) 也出现在列表中,它实际上是(27, 30) 的倒置并且出现在(18, 30) 范围内。它会删除这对(30, 27)
  • 如果有任何一对两个值中的 1 位于 (30, 27) 之间(因此在这种情况下,即使是 (100,30) 也会被删除。如果这不是你想要发生的事情,那么(30, 27) 应该被视为 (27, 30) 我建议只是切换它们。
  • 作为切换值的示例:var sorted = values.Select(x =&gt; x.Item1 &gt; x.Item2 ? (x.Item2, x.Item1) : x).ToList();
  • 作为一个问题y =&gt; x.CompareTo(y) 你为什么把它包括在内?
  • @KunalMukherjee 以便列表中的项目在与自身或自身重复时不会删除自身
【解决方案2】:

我相信这应该可行并且应该是 n*log(n):

//You will see some Math.Max and Math.Min - these are required because in your comments 
//you state the pairs can be out of order (the second value is less than the first)

int upper = int.MinValue;
values = values
    //Group all pairs by their minimum value, so (18,30) and (18,27) for example 
    //would be processed together
    .GroupBy(x => Math.Min(x.Item1, x.Item2))
    //Sort the groups based on their minimum value, so they can be processed in order. 
    //Although your example does not require this, the comments say this is required.
    .OrderBy(x => x.Key)
    //From the group [which may contain (18,30) and (18,27) for example],
    //only choose the one with the highest max value. This will choose (18,30)
    .Select(x => x.OrderBy(y => Math.Max(y.Item1, y.Item2)).Last())
    //Now iterate through the items and throw away the items which are inside
    //a pair previously processed pair. We use the upper variable to
    //keep track of the greatest processed upper bound to make throwing away 
    //previously processed pairs easy
    .Where(x =>
    {
        var max = Math.Max(x.Item1, x.Item2);
        if (upper < max)
        {
            upper = max;
            return true;
        }
        else
        {
            return false;
        }

    }).ToList();

如果没有 Linq,这当然可以更快,这取决于内存和性能对您的应用程序的重要性。

【讨论】:

  • 你能描述一下采取的方法吗,似乎有点冗长。
  • 我添加了一些 cmets。它比 n^2 解决方案更详细。您通常可以选择使用 n^2 或 nlog(n) 或 n 来解决问题,并且您通常会发现 n^2 很容易编写,nlog(n)有点难,而且你需要变得非常聪明。您需要考虑您的应用程序,考虑到速度、内存和可读性的平衡,哪些是最适合您的选择。
猜你喜欢
  • 2022-10-01
  • 1970-01-01
  • 2019-11-11
  • 1970-01-01
  • 2018-03-02
  • 1970-01-01
  • 1970-01-01
  • 2010-12-09
  • 1970-01-01
相关资源
最近更新 更多