【问题标题】:selecting and skipping elements选择和跳过元素
【发布时间】:2010-07-19 18:47:19
【问题描述】:

我正在尝试改进一些代码,但我想不出更好的方法来完成它目前的工作。本质上,我在外部循环以获取项目数除以我要选择的数字,然后在该循​​环内,我根据需要创建单个项目的项目数的内部循环选择项目,并通过外部循环值修改该项目,所以在下面的例子中,外循环循环两次(0,1),内循环每个外循环两次(0,1 然后 2,3)。

谁能看到一种更易读的方式来执行此操作,或者无需执行两个循环即可执行此操作?

希望这是有道理的。谢谢。

考虑 XML

string xml = @"
<MainItem>
 <Select>2</Select>
 <ItemArray>
   <Item>One</Item>
   <Item>Two</Item>
   <Item>Three</Item>
   <Item>Four</Item>
 </ItemArray>
</MainItem>";

var doc = XDocument.Parse(xml);

这里的 Select 值告诉我有多少项目创建一个“对象”,所以在这种情况下,2 个项目是一个对象(这可以是任何数字,但项目的数量将始终允许正确数量的对象)目前我是做类似的事情

    List<List<XElement>> items = new List<List<XElement>>();
    for(int i = 0;i < (doc.Descendants("Item").Count() / (int)doc.Element("MainItem").Element("Select"));i++)
    {
      //this is one object
     var singleItem = new List<XElement>();
      for (int j = 0; j <  (int)doc.Element("MainItem").Element("Select"); j++)
     {
         var item =  doc.Descendants("Item").ElementAt(j + (i * (int)doc.Element("MainItem").Element("Select")));
         singleItem.Add(item);
     }
     items.Add(singleItem);
    }

所以我们以一个包含 2 个项目的 List 列表结束,每个项目包含 2 个 XElement(一个和两个一起,三个和四个一起) 所以..

ItemOne
 One
 Two
ItemTwo
 Three
 Four

【问题讨论】:

  • 您可能应该格式化您的 XML 并显示您期望的 XML 输出示例。
  • @Winston Smith 已按要求完成,感谢您的意见
  • 你要重新计算这个(int)doc.Element("MainItem").Element("Select")多少次?
  • 分组是怎么做的?如果有 5 个项目和Select=2
  • @Darin Dimitrov 关于重新计算绝对正确,这是我将完全删除或在完成的代码中计算一次的区域,就我所说的分组而言,由于数据的方式构造 5 个项目选择 2 不会发生,如果有意义的话,它总是会创建足够的项目来创建均匀数量的组?

标签: c# linq .net-3.5 linq-to-xml


【解决方案1】:

有一种简单的方法可以使用单个 LINQ 语句来完成。可以按item index / batchSize分组,如下:

int batchSize = (int)doc.Element("MainItem").Element("Select");
var items = doc
            .Descendants("Item")
            .Select( (e, i) => new {i,e} )
            .GroupBy( g => g.i / batchSize )
            .Select( g => g.Select( gv => gv.e) )
            ;

这会在您描述的结构中给出IEnumerable&lt;IEnumerable&lt;XElement&gt;&gt;

【讨论】:

    【解决方案2】:
    public static IEnumerable<List<T>> Batch<T>(
      this IEnumerable<T> source,
      int batchAmount) 
    { 
      List<T> result = new List<T>(); 
      foreach(T t in source) 
      { 
        result.Add(t); 
        if (result.Count == batchSize) 
        { 
          yield return result; 
          result = new List<T>(); 
        } 
      } 
      if (result.Any()) 
      { 
        yield return result; 
      } 
    } 
    

    调用者

    int batchAmount = (int)doc.Element("MainItem").Element("Select"));
    
    List<List<XElement>> items = doc.Descendants("Item")
      .Batch(batchAmount)
      .ToList();
    

    【讨论】:

    • 希望我能接受 2 个答案 +1,它可以工作并达到我所需要的,你的答案和接受的答案之间的唯一区别是需要扩展方法
    • Winston Smith 的回答很酷(我以前写过),但在使用超过 10,000 个元素时速度很慢。
    猜你喜欢
    • 2014-07-09
    • 1970-01-01
    • 1970-01-01
    • 2022-10-13
    • 1970-01-01
    • 2012-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多