【问题标题】:Select given ranges of indexes from source array从源数组中选择给定的索引范围
【发布时间】:2016-08-22 17:36:21
【问题描述】:

我想用数组的索引创建一个数组。假设我有一个这样的数组:

| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

我从查询中得到的结果如下:

这意味着地点 13, 4 (LengthUnit = 2) 和 7 很忙(已被占用)。所以,数组现在看起来像:

| T | 2 | T | T | 5 | 6 | T | 8 | 9 | 10 |

其中,T 代表拍摄。

如何使用查询结果创建两个整数数组,如下所示:

int[] taken = { 1, 3, 4, 7 };
int[] notTaken = { 2, 5, 6, 8, 9, 10 };

【问题讨论】:

  • 循环查询结果和 Skip() 和 Take() 适当的索引?你试过什么?
  • start Unit has 1, 3, 7 howz 4被占用了?
  • @yogi 这在问题中没有解释,但鉴于 3 的 LengthUnit 为 2,我假设 OP 希望从 3 开始获取 2 条记录。
  • @CodeCaster 你是对的
  • @yogi 2 是从起始单位开始的长度单位。所以,3,4被拍了

标签: c# .net arrays


【解决方案1】:

Enumerable.Range 证明在这种情况下有用:

Dictionary<int, int> startAndLength = new Dictionary<int, int>()
                                      { { 1, 1 }, { 3, 2 }, { 7, 1 } };

int[] taken = startAndLength
              .SelectMany(kvp => Enumerable.Range(kvp.Key, kvp.Value)).ToArray();

int[] notTaken = Enumerable.Range(0, 10).Except(taken).ToArray();

开始创建一组起点和长度,然后使用Enumerable.Range 确定已采取的项目。然后再次使用Enumerable.Range 来确定没有被拿走的项目。

【讨论】:

    【解决方案2】:

    使用Enumerable.Range 创建您想要的项目集合。然后使用Except获取其他人。

    List<int> values = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    
    List<Tuple<int, int>> ranges = new List<Tuple<int, int>>
    {
        new Tuple<int, int>(1,1),
        new Tuple<int, int>(3,2),
        new Tuple<int, int>(7,1),
    };
    
    var t = ranges.SelectMany(range => Enumerable.Range(range.Item1, range.Item2)).ToList();
    
    // Here I decide to use Intersect instead of just having t for the case 
    // where you requested a range that doesn't exist
    var taken = values.Intersect(t).ToArray();
    var notTaken = values.Except(taken).ToList();
    

    如果您想要这些值并且它们不是连续的,就像示例中那样:创建所有所需索引的集合,然后获取这些索引的所有项目:

    var indexes = ranges.SelectMany(range => Enumerable.Range(range.Item1, range.Item2)).Select(item => item - 1).ToList();
    
    var taken = values.Where((item, index) => indexes.Contains(index)).ToList();
    var notTaken = values.Where((item, index) => !indexes.Contains(index)).ToList();
    

    【讨论】:

      【解决方案3】:

      一点 Linq 会让你走得很远:

      public class QueryResult
      {
          public int StartUnit { get; set; }
          public int LengthUnit { get; set; }
      }
      
      var input = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
      
      var queryResult = new QueryResult[]
      {
          new QueryResult { StartUnit = 1, LengthUnit = 1 },
          new QueryResult { StartUnit = 3, LengthUnit = 2 },
          new QueryResult { StartUnit = 7, LengthUnit = 1 },
      };
      
      var taken = new List<int>();
      
      taken.AddRange(queryResult.SelectMany(q => (input.Skip(q.StartUnit - 1).Take(q.LengthUnit))));
      
      Console.WriteLine("Taken: {0}", string.Join(",", taken));
      
      var notTaken = input.Except(taken);
      
      Console.WriteLine("Not taken: {0}", string.Join(",", notTaken));
      

      使用SelectMany()Skip()Take(),您可以选择要包含的范围。使用Except(),你可以得到没有被拿走的物品。

      请注意,这将执行得非常糟糕,因为它迭代集合的次数太多了。它还假设 StartUnit 实际上表示输入集合中的一个 (index + 1),而不是一个值。

      如果您实际上不想查看输入数组,并且值始终是连续的(即输入中没有空洞),您可以使用 Enumerable.Range() 生成请求的范围:

      taken.AddRange(queryResult.SelectMany(q => Enumerable.Range(q.StartUnit, q.LengthUnit)));
      

      并生成要排除的 Except() 的完整范围:

      var notTaken = Enumerable.Range(1, 10).Except(taken);
      

      当然,如果您希望输出实际上是数组,请在此处和此处调用 ToArray()

      【讨论】:

      • @Tim 但它假定输入始终是连续的。
      猜你喜欢
      • 2018-05-29
      • 1970-01-01
      • 1970-01-01
      • 2017-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-28
      • 1970-01-01
      相关资源
      最近更新 更多