【问题标题】:How to delete first column in all datatables within a collection of datatables C#如何删除数据表集合中所有数据表中的第一列C#
【发布时间】:2020-10-13 23:49:54
【问题描述】:

我需要检查从 Sybase 查询返回的数据,以检查与将显示给定数据集的电子表格相对应的第一列。我可以在我的数据集中正确获取数据,但是当我尝试删除分组列时问题就来了。

我的样本数据如下:

public static DataTable JustDataTableWithSheetColumn()
{
    var sample = new DataTable();

    sample.Columns.Add("SomethingSheet", typeof(string));
    sample.Columns.Add("Column1", typeof(string));
    sample.Columns.Add("Column2", typeof(string));

    sample.Rows.Add("1", "Somestuff", "this other stuff");
    sample.Rows.Add("1", "Fluffy", "this stuff");
    sample.Rows.Add("2", "ToolShed", "this other stf");
    sample.Rows.Add("2", "FudgeCycles", "this oer stuff");
    sample.Rows.Add("2", "Crap", "thr stuff");
    sample.Rows.Add("2", "stuff and stuff", "thiuff");
    sample.Rows.Add("2", "test crap", "this  stuff");
    sample.Rows.Add("2", "dungheap", "this othuff");
    sample.Rows.Add("3", "people eater", "this other stf");
    sample.Rows.Add("3", "no purple people", "ths oth stff");

    return sample;
}

以下正确分组并将它们应用于数据表:

var thing = DataTableExamples.JustDataTableWithSheetColumn();

if (thing.Columns[0].ColumnName.Contains("Sheet"))
{
    var test = from t in thing.AsEnumerable()
        group t by t.ItemArray[0]
        into g
        select g.ToList().CopyToDataTable();
}

我尝试不使用 .CopyToDataTable() 来仅拥有 DataRows 的集合,并尝试使用 Skip(1) 查询那些,但我认为我的操作顺序不正确,或者我在那个星云中,我有时会迷失在其中IEnumerable 与 IQueryable 以及所有这些变体。

像这样:

datarow.ItemArray.Skip(1).ToArray();

我也尝试循环遍历数据表集合并使用 dt.RemoveAt(0) 但我无法引用操纵的数据表(或这样做不正确)。

foreach (var dt in test)
{ 
    dt.Columns.RemoveAt(0);
}

最重要的是,从数据库返回的数据的第一列在我将它们转换为数据表以便以后添加到我从该 API 返回的数据集中后,就不需要显示或使用它们。

因此,我正在寻找一种优雅的方式,以尽可能少的装箱和拆箱来获得我需要的东西。这部分必须在将其添加到最终数据集之前完成,因为这些奇怪的存储过程中的每一个都可能返回不同的数据表结构,因此我不能简单地从最终数据集中删除所有第一列。

感谢您的帮助。

【问题讨论】:

  • 你想要没有第一列的相同数据表吗?
  • @Sajid 那将是理想的。我在淋浴时想到我可能必须在填充数据表之前删除列,但还没有尝试过。我还需要保持相同的基本结构,即每列的数据类型以及列的名称。
  • @Sajid 需要明确的是,在这种情况下,我需要同一张表 3 次,而不是第一列。
  • 我以为我理解你,直到我读到最后一段。您的问题标题说 “如何删除数据表 C# 集合中所有数据表中的第一列” 并且您的最终段落说 “我不能简单地从末尾删除所有第一列数据集” - “数据表的集合”是“最终数据集”的子集吗?这个保存“数据表集合”的变量在哪里?
  • @CaiusJard 道歉...这个数据表集合将被添加到数据集以传输到调用 API,该数据集可能有其他数据表没有第一个烦人的列。

标签: c# linq datatables dataset .net-4.7.2


【解决方案1】:

dr.ItemArray.Skip(1).ToArray();

我怀疑这个(无论是什么博士——你的问题中没有提到)被用在了错误的地方,你最终在分组完成之前删除了你想要分组的列

使用 Skip(1) 查询那些

虽然跳过数据行不会帮助您跳过一列 - 它只会删除第一整行数据


您可以在准备好之后直接删除该列,而不是陷入任何令人费解的事情:

if (thing.Columns[0].ColumnName.Contains("Sheet"))
{
    var test = from t in thing.AsEnumerable()
        group t by t.ItemArray[0]
        into g
        select g.ToList().CopyToDataTable();

    foreach(var dt in test){
        dt.Columns.RemoveAt(0);
        endDataSet.Tables.Add(dt);
    }
}

或者您可以操作结果数据集:

    //referencing known table names
    var dtToStrip = new[] { "ATableName", "BTableName" }
    foreach(DataTable dt in endDataSet.Tables)
      if(dtToStrip.Contains(dt.TableName))
        dt.Columns.RemoveAt(0);

    //or removing any column named sheet from any table in the set
    foreach(DataTable dt in endDataSet.Tables)
      if(dt.Columns.Count > 0 && dt.Columns[0].ColumName.Contains("Sheet"))
        dt.Columns.RemoveAt(0);

【讨论】:

  • 我确实尝试过遍历数据表,但由于某种原因,当我引用“测试”将其放入最终数据集中时,我仍然有这些列。
  • 我进行了编辑 - 解释是对您的回答的评论
【解决方案2】:

我相信我是本案延期执行的受害者。

最初,我正在执行以下操作:

if (thing.Columns[0].ColumnName.Contains("Sheet"))
{
    var test = from t in thing.AsEnumerable()
        group t by t.ItemArray[0]
        into g
        select g.ToList().CopyToDataTable();

    foreach (var dt in test)
    { 
        dt.Columns.RemoveAt(0);
    }

    ds.Tables.AddRange(test.ToArray());
}

我错误地认为是在执行第一个.ToList() 时执行查询。但直到我在最后将它添加到 DataSet 时执行了.ToArray(),它才被执行。如果我理解正确的话,这意味着我 foreach 中的处决都是徒劳的,因为它们是独立处决的。

如果我先将 .ToArray() 移动到 LINQ 查询,它似乎可以工作:

if (thing.Columns[0].ColumnName.Contains("Sheet"))
{
    var test = (from t in thing.AsEnumerable()
        group t by t.ItemArray[0]
        into g
        select g.ToList().CopyToDataTable()).ToArray();

    foreach (var dt in test)
    { 
        dt.Columns.RemoveAt(0);
    }

    ds.Tables.AddRange(test);
}

感谢您的帮助。

如果我的结论不正确,或者我遗漏了一些逻辑,请告诉我,因为某些点会使这对遇到类似问题的其他开发者更有帮助。

【讨论】:

  • 这不是一个延迟执行的事情; LINQ 查询在您在 for 循环中枚举时执行,只是在您执行 ds.Tables.AddRange 时它再次执行。如果您将ds.Tables.Add 调用放入 for 循环,则它在没有ToArray() 的情况下“按预期工作”。测试是一个查询;您可以使用 ToArray 实现它(这有点浪费),也可以在枚举时使用结果。如果没有 ToArray 和 for+addrange,则进行查询,运行它,在 for 中枚举它,丢弃结果,然后 AddRange 进行自己的枚举/运行..
  • @CaiusJard 你能详细说明为什么它“有点浪费”吗?我试图确保在必要时利用延迟执行,但如果我只需要收集结果,一旦我觉得获得所需的东西会“更便宜”,然后在那时操作对象集合。我意识到在这两种情况下都会发生这种情况,但我想我不明白在你提到的差异的背后发生了什么。
  • 这本身不是延迟执行; LINQ 是延迟执行,无论你在制定查询后做的第一件事是 ToArray() 它还是 foreach 它,你都在执行它并枚举所以没有什么是 deferred (比它更长否则已经)。我声称让 LINQ 从可枚举中准备一个数组然后枚举该数组是一个浪费的步骤,仅仅是因为可以枚举一个可枚举的,所以创建数组的过程必须是一个浪费的步骤。另见stackoverflow.com/questions/1105990/…
  • (我应该澄清“这是一个浪费的步骤在这种情况下” - 在 linq 查询上调用 ToXxx 以运行查询并实现结果到集合中并保留集合是您想要做的..您也可以说 foreaching 并将表放入数据集中是同一件事,您是对的;我们在这种情况下这样做是因为我们想要一个数据集,并且没有一个 ToDataSet() 可以将 IEnumerable<DataTable> 转换为 DataSet(本身就是一个“数据表集合”),就像有一个 ToArray 可以将 IEnumerable<sring> 转换为 string[]
猜你喜欢
  • 2015-03-05
  • 2012-04-25
  • 2014-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多