【问题标题】:unequal size lists to merge要合并的大小不等的列表
【发布时间】:2013-09-21 05:44:22
【问题描述】:

我搜索过类似的情况如下。

我有两个列表,列表 A 和列表 B。
列表 A 由从仅包含字符串的 ClassA 创建的 10 个对象组成。
列表 B 由从 ClassB 创建的 100 个对象组成,其中仅包含小数。

List A 是头信息。
列表 B 是数据信息。

这两个列表的关系是:

Row 1 of list A corresponds to rows 1-10 of list B.
Row 2 of list A corresponds to rows 11-20 of list B.
Row 3 of list A corresponds to rows 21-30 of list B.

等等…………

如何组合这两个列表,以便当我在控制台上显示它们时,用户会看到一个标题行,紧接着是相应的 10 个数据行。

如果之前已经回答过这个问题,我深表歉意。

【问题讨论】:

  • 所以列表 A 将 总是 包含 10 个对象,而列表 B 将 总是 包含 100 个对象?
  • 我正在从文本文件中读取,A 中的对象数量可能会有所不同。
  • @greg 你的意思是列表 B 中的 10 个对象对应于列表 A 中的每 1 个对象吗?
  • 对于任何混淆,我深表歉意。对于列表 A 中的每 1 个对象,列表 B 中就有 10 个对应的对象。列表 A 中的第一个对象对应于列表 B 中的前 10 个对象,依此类推.....

标签: c# list merge


【解决方案1】:

好的,应该可以的。让我知道,以防我有什么问题。

List<ClassA> listA = GetListA()// ...
List<ClassB> listB = GetListA()// ...


if(listB.Count % listA.Count != 0)     
      throw new Exception("Unable to match listA to listB");

var datasPerHeader = listB.Count / listA.Count;

for(int i = 0; i < listA.Count;i++)
{
    ClassA header = listA[i];
    IEnumerable<ListB> datas = listB.Skip(datasPerHeader*i).Take(datasPerHeader);
    Console.WriteLine(header.ToString());
    foreach(var data in datas)
    {
          Console.WriteLine("\t{0}", data.ToString());
    } 
}

【讨论】:

  • +1 在你的 mod 检查上...我把它作为练习留给了海报,但基本上是逐字记录。
  • 感谢您的帮助,它运行良好。我的编程经验有限,我最能理解你的例子。 IEnumerable 接口是我以前没有使用过的,但很快就会使用。我仍在寻找组合包含不同类型的列表的方法。
  • 酷,很高兴听到这个消息。 IEnumerable 是泛化所有集合的接口,例如.net 中的所有数组、列表、序列、哈希表、字典都实现了 IEnumerable,这意味着它们是某些项目的序列/集合,并且可以枚举。
【解决方案2】:

这里有一些代码可以满足您的要求 - 我将找到分区扩展的链接,因为我在我的代码中找不到它了:

void Main()
{
    List<string> strings = Enumerable.Range(1,10).Select(x=>x.ToString()).ToList();
    List<decimal> decimals = Enumerable.Range(1,100).Select(x=>(Decimal)x).ToList();

    var detailsRows = decimals.Partition(10)
                              .Select((details, row) => new {HeaderRow = row, DetailsRows = details});

    var headerRows = strings.Select((header, row) => new {HeaderRow = row, Header = header});

    var final = headerRows.Join(detailsRows, x=>x.HeaderRow, x=>x.HeaderRow, (header, details) => new {Header = header.Header, Details = details.DetailsRows});
}

public static class Extensions
{
    public static IEnumerable<List<T>> Partition<T>(this IEnumerable<T> source, Int32 size)
    {
        for (int i = 0; i < Math.Ceiling(source.Count() / (Double)size); i++)
            yield return new List<T>(source.Skip(size * i).Take(size));
    }
}    

那个 Partition 方法是完成繁重工作的方法......

这里是文章的链接 - LINK

编辑 2

这里是Main() 方法的更好代码... 急忙回答忘记了大脑:

void Main()
{
    List<string> strings = Enumerable.Range(1,10).Select(x=>x.ToString()).ToList();
    List<decimal> decimals = Enumerable.Range(1,100).Select(x=>(Decimal)x).ToList();

    var detailsRows = decimals.Partition(10);

    var headerRows = strings; //just renamed for clarity from other code

    var final = headerRows.Zip(detailsRows, (header, details) => new {Header = header, Details = details});
}

【讨论】:

  • 顺便说一句,我使用 LinqPad 来提供我的示例,因此您应该能够复制/粘贴它并在 C# 程序模式下运行它。
【解决方案3】:

这应该很简单,除非我遗漏了什么。

var grouped = ListA.Select((value, index) => 
  new {
    ListAItem = value,
    ListBItems = ListB.Skip(index * 10).Take(10)
  })
  .ToList();

返回一个可以循环的匿名类型。

foreach (var group in grouped)
{
  Console.WriteLine("List A: {0}", group.Name);
  foreach (var listBItem in group.ListBItems)
  {
    Console.WriteLine("List B: {0}", listBItem.Name);
  {
}

【讨论】:

    【解决方案4】:

    最简单的方法可能是这样的:

    var listA = new List<string>() { "A", "B", "C", ... }
    var listB = new List<decimal>() { 1m, 2m, 3m, ... }
    double ratio = ((double)listA.Count) / listB.Count;
    var results = 
        from i in Enumerable.Range(0, listB.Count)
        select new { A = listA[(int)Math.Truncate(i * ratio)], B = listB[i] };
    

    或者用流利的语法:

    double ratio = ((double)listA.Count) / listB.Count;
    var results = Enumerable.Range(0, listB.Count)
        .Select(i => new { A = listA[(int)Math.Truncate(i * ratio)], B = listB[i] });
    

    当然,如果您知道对于listA 中的每个项目,listB 中的每个项目总是有 10 个项目,您可以将其简化为:

    var results = 
        from i in Enumerable.Range(0, listB.Count)
        select new { A = listA[i / 10], B = listB[i] };
    

    或者用流利的语法:

    var results = Enumerable.Range(0, listB.Count)
        .Select(i => new { A = listA[i / 10], B = listB[i] });
    

    这将返回一个类似的结果集

    { { "A", 1 }, 
      { "A", 2 }, 
      { "A", 3 }
      ..,
      { "A", 10 },
      { "B", 11 },
      { "B", 12 },
      { "B", 13 },
      ...
      { "B", 20 },
      { "C", 21 },
      ...
      { "J", 100 }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-09-18
      • 2017-12-26
      • 1970-01-01
      • 2012-07-04
      • 2011-11-13
      • 1970-01-01
      • 2022-11-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多