【问题标题】:c# linq join on a sublist in a listc# linq 加入列表中的子列表
【发布时间】:2013-02-07 15:10:45
【问题描述】:

我有一个列表:var_assets_root,它有一个嵌套的子列表:contents。我可以在根列表上进行连接,并通过对var_assets_root 中的索引项进行两次连接,使用另外两个列表lst_invtypes_assetslst_stations_composite_retribution 中的额外项来扩充它。但我也想对子列表var_assets_root-->contents\b.contents 中的项目进行连接,到目前为止,下面的代码还没有这样做。 Image>>structure of var_assets_root in watch window

mysql mysql_object = new mysql();
  List<mysql.invtypes_asset> lst_invtypes_assets = mysql_object.dbmysql_invtypes_asset_to_list();
  List<mysql.stations_composite_retribution> lst_stations_composite_retribution = mysql_object.dbmysql_select_stastations_composite_retribution_to_list();
  var lst_assets_list = new AssetList("134399", "343434SxSFX7qO81LqUCberhS1OQtktMvARFGED0ZRSN5c4XP230SA", "434367527");
  lst_assets_list.Query();
  var var_assets_root = lst_assets_list.assets.ToList();

  var var_assets_root_typeid_station 
    = from b in var_assets_root
    join c in lst_invtypes_assets on b.typeID equals c.typeID
    join d in lst_stations_composite_retribution on b.locationID equals d.stationID
    select new {b.contents, b.flag, b.itemID, b.locationID, d.solarSystemName, d.security, d.securityClass, d.regionName, b.quantity, b.singleton, b.typeID, c.groupID, c.marketGroupID, c.volume,
      c.typeName, c.description};

我已经完成了为每个内容子列表运行 linq 查询并相应地分配值的解决方案。

private void btn_evenet_Click(object sender, EventArgs e)
{
  Stopwatch stopwatch1 = new Stopwatch();
  Stopwatch stopwatch2 = new Stopwatch();
  stopwatch1.Start();
  mysql mysql_object = new mysql();
  List<mysql.invtypes_asset> lst_invtypes_assets = mysql_object.dbmysql_invtypes_asset_to_list();
  List<mysql.stations_composite_retribution> lst_stations_composite_retribution = mysql_object.dbmysql_select_stastations_composite_retribution_to_list();
  AssetList lst_assets_list = new AssetList("2312099", "J&VNM14RFUkSxSFX7qAAAAAA1OQtktMvYTVZZBhkO23235c4Z&HJKODPQLM", "123231527");
  lst_assets_list.Query();
  var var_assets_root = lst_assets_list.assets.ToList();
  var var_assets_root_typeid_station 
    = from b in var_assets_root
    join c in lst_invtypes_assets on b.typeID equals c.typeID
    join d in lst_stations_composite_retribution on b.locationID equals d.stationID
      select new { b.contents, b.flag, b.itemID, b.locationID, d.solarSystemName, d.security, d.securityClass, d.regionName, b.quantity, b.singleton, b.typeID, c.groupID, c.marketGroupID, c.volume,
      c.typeName, c.description};
  var lst_assets_root_typeid_station = var_assets_root_typeid_station.ToList(); // Using .ToArray() is about 200ms faster than .ToList()
  stopwatch2.Start(); 
  for (Int32 a = 0; a < lst_assets_root_typeid_station.Count(); a++)
  {
    if (lst_assets_root_typeid_station[a].contents.Count() >= 0)
    {
      for (Int32 b = 0; b < lst_assets_root_typeid_station[a].contents.Count(); b++)
      {
        var var_row_invtypes_assets = lst_invtypes_assets.Where(x => x.typeID == lst_assets_root_typeid_station[a].contents[b].typeID).ToArray();
        lst_assets_root_typeid_station[a].contents[b].groupID = var_row_invtypes_assets[0].groupID;
        lst_assets_root_typeid_station[a].contents[b].typeName = var_row_invtypes_assets[0].typeName;
        lst_assets_root_typeid_station[a].contents[b].description = var_row_invtypes_assets[0].description;
        lst_assets_root_typeid_station[a].contents[b].volume = var_row_invtypes_assets[0].volume;
        lst_assets_root_typeid_station[a].contents[b].marketGroupID = var_row_invtypes_assets[0].marketGroupID;
        if (lst_assets_root_typeid_station[a].contents[b].contents.Count() != 0)
        {
          for (Int32 c = 0; c < lst_assets_root_typeid_station[a].contents[b].contents.Count(); c++)
          {
            var_row_invtypes_assets = lst_invtypes_assets.Where(x => x.typeID == lst_assets_root_typeid_station[a].contents[b].contents[c].typeID).ToArray();
            lst_assets_root_typeid_station[a].contents[b].contents[c].groupID = var_row_invtypes_assets[0].groupID;
            lst_assets_root_typeid_station[a].contents[b].contents[c].typeName = var_row_invtypes_assets[0].typeName;
            lst_assets_root_typeid_station[a].contents[b].contents[c].description = var_row_invtypes_assets[0].description;
            lst_assets_root_typeid_station[a].contents[b].contents[c].volume = var_row_invtypes_assets[0].volume;
            lst_assets_root_typeid_station[a].contents[b].contents[c].marketGroupID = var_row_invtypes_assets[0].marketGroupID;
          }
        }
      }         
    }
  }
  stopwatch2.Stop();
  stopwatch1.Stop();
  lbl_stopwatch1.Text = "Everything: " +  stopwatch1.Elapsed.ToString("mm\\:ss\\.ff"); // 1.53 seconds no debugging
  lbl_stopwatch2.Text = "contents sublists: " +  stopwatch2.Elapsed.ToString("mm\\:ss\\.ff"); // contents sublists take 1.03 seconds no debugging
}
 }

一旦我发现在调用 getAllContents 时“yield”会从一堆内容节点中弹出一个内容节点,我调整了我的代码和您的函数,以便现在所有内容节点都被递归到并从 linq 查询中填充它们的空值.此外,在 var_assets_root_typeid_station 的 linq 创建之后的新代码现在几乎快了两倍。谢谢。

private void btn_evenet_Click(object sender, EventArgs e)
{
  Stopwatch stopwatch1 = new Stopwatch();
  Stopwatch stopwatch2 = new Stopwatch();
  stopwatch1.Start();
  mysql mysql_object = new mysql();
  List<mysql.invtypes_asset> lst_invtypes_assets = mysql_object.dbmysql_invtypes_asset_to_list();
  List<mysql.stations_composite_retribution> lst_stations_composite_retribution = mysql_object.dbmysql_select_stastations_composite_retribution_to_list();
  AssetList lst_assets_list = new AssetList("12345678", "ABCDEFFGHIKL01235kokJDSD213123", "12345678");
  lst_assets_list.Query();
  var var_assets_root = lst_assets_list.assets.ToList();
  var var_assets_root_typeid_station 
    = from b in var_assets_root
    join c in lst_invtypes_assets on b.typeID equals c.typeID
    join d in lst_stations_composite_retribution on b.locationID equals d.stationID
      select new 
        {b.contents, b.flag, b.itemID, b.locationID, d.solarSystemName, d.security, d.securityClass, d.regionName, b.quantity, b.singleton, b.typeID, c.groupID, c.marketGroupID, c.volume,
      c.typeName, c.description};
  var lst_assets_root_typeid_station = var_assets_root_typeid_station.ToList(); // Using .ToArray() is about 200ms faster than .ToList()
  stopwatch2.Start(); 
 for (Int32 a = 0; a < lst_assets_root_typeid_station.Count(); a++)
  {
    if (lst_assets_root_typeid_station[a].contents.Count() > 0)
    {
      for (Int32 z = 0; z < lst_assets_root_typeid_station[a].contents.Count(); z++)
      {
        foreach (AssetList.Item contentnode in getAllContents(lst_assets_root_typeid_station[a].contents[z]))
        {
          var var_row_invtypes_assets = lst_invtypes_assets.Where(x => x.typeID == contentnode.typeID).ToArray();
          contentnode.groupID = var_row_invtypes_assets[0].groupID;
          contentnode.typeName = var_row_invtypes_assets[0].typeName;
          contentnode.description = var_row_invtypes_assets[0].description;
          contentnode.volume = var_row_invtypes_assets[0].volume;
          contentnode.marketGroupID = var_row_invtypes_assets[0].marketGroupID;
        }
      }
    }
  }    
  stopwatch2.Stop();
  stopwatch1.Stop();
  lbl_stopwatch1.Text = "Everything: " +  stopwatch1.Elapsed.ToString("mm\\:ss\\.ff"); // 1.16 seconds no debugging
  lbl_stopwatch2.Text = "contents sublists: " +  stopwatch2.Elapsed.ToString("mm\\:ss\\.ff"); // contents sublists take 0.63 seconds no debugging
}

IEnumerable<AssetList.Item> getAllContents(AssetList.Item contentNode)
{
  if (contentNode.contents.Count == 0)
  {
    yield return contentNode;
  }
  else
  {
    foreach (AssetList.Item subContentNode in contentNode.contents)
    {
      yield return subContentNode;
      foreach (AssetList.Item subSubContentNode in getAllContents(subContentNode))
        yield return subSubContentNode;
    }
  }
}

【问题讨论】:

  • 您确实应该努力遵守标准命名约定。这将使您的代码更易于阅读。
  • @Servy 也许发布者的代码符合特定组的标准命名约定。但是,我同意在发布到 SO 之前进行一些编辑可能会有用。
  • 我是一个业余爱好者新手编码器。我使用了对自己来说很直观的命名。将来我会尝试采用标准的命名约定

标签: c# .net linq join


【解决方案1】:

您不只是在寻找 SelectMany 吗?

var contents = lst_invtypes_assets.contents.SelectMany(x => x.contents);

【讨论】:

  • 我如何在 linq 查询中使用 .SelectMany() var var_assets_root_typeid_station = ... 所以我可以对内容子列表进行连接。
【解决方案2】:

我认为您想要访问外部 .contents 属性,如果它包含任何 contents,那么也访问这些,等等......递归。

虽然您可以通过定义递归 Func&lt;AssetList.Item, IEnumerable&lt;AssetList.Item&gt;&gt; 和使用 .Aggregate 的一行 LINQ 来做到这一点,但定义自己的递归方法可能更容易/更易读。

IEnumerable<AssetList.Item> getAllContents(AssetList.Item station) {
    foreach (AssetList.Item subStation in station.contents) {
        yield return subStation;
        foreach (AssetList.Item subSubStation in getAllContents(substation))
            yield return subSubStation;
    }
}

然后你可以做一个简单的foreach(var station in getAllContents(parentStation)),或者修改它以包含原始站,使其成为扩展方法等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-09
    • 1970-01-01
    • 2012-04-24
    相关资源
    最近更新 更多