【问题标题】:Get n (part of) objects from a list of objects, starting from n index从对象列表中获取 n(部分)对象,从 n 索引开始
【发布时间】:2019-04-30 20:37:51
【问题描述】:

我有一个包含 n 个对象的列表。我想从选定的索引开始最多抓取 n 个项目(-n 个以前的项目和 n + 下一个项目)。我想要一个方法,在其中我为列表提供某些参数。

如何在 C# 中实现这一点?

第一个例子:
int selectedIndex = 5
int itemsToTake = 4(2 个上一个和 2 个下一个)
返回列表 = 3-4-5-6-7

第二个例子:
int selectedIndex = 1
int itemsToTake = 4(前 1 个,后 3 个,因为列表以 0 开头)
返回列表 = 0-1-2-3-4

我已经尝试过list.skip().take()的组合,只是效果不太好。

示例:

nextIndex = nextIndex - prevIndex + 1;
return List.Skip (prevIndex) .Take (nextIndex) .ToList ();

【问题讨论】:

    标签: c# list linq


    【解决方案1】:

    一种低效但视觉美观的方式:

    public static IEnumerable<T> Nearby<T>(this IEnumerable<T> source,
        int selectedIndex, int itemsToTake)
    {
        var left = source.Take(selectedIndex).Reverse().Take(itemsToTake / 2).Reverse();
        var middle = source.ElementAt(selectedIndex);
        var right = source.Skip(selectedIndex).Skip(1).Take(itemsToTake / 2);
        return left.Append(middle).Concat(right);
    }
    

    使用示例:

    var source = Enumerable.Range(0, 10);
    Console.WriteLine($"Result: {String.Join(", ", source.Nearby(5, 5))}");
    

    输出:

    结果:3、4、5、6、7

    【讨论】:

      【解决方案2】:

      Skip + Take 应该可以正常工作,试试这个:

      int firstIndex = selectedIndex - itemsToTake / 2;
      firstIndex = firstIndex < 0 ? 0 : firstIndex;
      return list.Skip(firstIndex).Take(itemsToTake);
      

      【讨论】:

        【解决方案3】:

        首先,确保列表包含足够的元素:

        if(itemsToTake  + 1 > List.Count)
            return List.ToList(); //copy the list
        

        您要采用的第一个索引是(不考虑序列边界):

        var firstIndex = selectedIndex - itemsToTake  / 2;
        

        对应的最后一个索引是firstIndex + n

        然后,确保范围有效

        if(firstIndex < 0) 
            firstIndex = 0;
        if(firstIndex + nitemsToTake >= List.Count)
            firstIndex = List.Count - 1 - itemsToTake ;
        

        最后按照你的方法去做:

        return List.Skip(firstIndex).Take(itemsToTake  + 1).ToList();
        

        【讨论】:

          【解决方案4】:

          selectedIndex - itemsToTake / 2小于0的特殊情况需要处理:

          public static List<T> Take<T>(this List<T> list, int selectedIndex, int itemsToTake) {
              if (selectedIndex - n / 2  < 0) {
                  return list.Take(itemsToTake + 1).ToList();
              }
              return list.Skip(selectedIndex - itemsToTake / 2).Take(itemsToTake +1).ToList();
          }
          

          【讨论】:

            【解决方案5】:
            public static IEnumerable<T> Nearby<T>(IEnumerable<T> source, int selectedIndex, int itemsToTake)
            {
              itemsToTake = ((itemsToTake/2)*2)+1;
              Queue<T> queue = new Queue<T>();
              bool foundItem = false;
              int afterItemCount = 0;
              int recommendedAfterItemCount = itemsToTake/2;
              foreach(var pair in source.Select((t, i) => new {t, i}))
              {
                T t = pair.t;
                int i = pair.i;
            
                queue.Enqueue(t);
                if (itemsToTake < queue.Count) queue.Dequeue();
            
                if (i == selectedIndex) foundItem = true;
                else if (foundItem) afterItemCount += 1;
            
                bool enoughItems = queue.Count == itemsToTake;
                bool enoughAfterItems = recommendedAfterItemCount <= afterItemCount;
                if (enoughItems && enoughAfterItems) break;
            
              }
              foreach(T t in queue)
              {
                yield return t;
              }
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-04-13
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多