【问题标题】:Iterate over items in Tuple迭代元组中的项目
【发布时间】:2017-11-09 08:36:13
【问题描述】:

我有这个方法有三个循环:

    public void Print(Tuple<List<DateTime>, List<double>, List<string>> dataToPrint)
    {
        foreach (var item in dataToPrint.Item1)
        {
            Console.WriteLine(item);
        }
        foreach (var item in dataToPrint.Item2)
        {
            Console.WriteLine(item);
        }
        foreach (var item in dataToPrint.Item3)
        {
            Console.WriteLine(item);
        }
    }

是否可以只使用一个循环在屏幕上打印所有带有列表内容的项目?

【问题讨论】:

  • 改类型有问题吗?
  • 你为什么还要在这里使用Tuple?如果所有列表的长度相同,那么无论如何都使用List&lt;Tuple&lt;...&gt;&gt;,如果不是,则只需实现一个打印出列表的构建器方法,并调用它3次。
  • 这就是我在@InBetween 的想法,但它们的长度可能不一样
  • 您显示的打印顺序是要求吗?即第一个列表中的所有项目,然后是第二个列表中的所有项目等。或者你可以拥有每个列表的第 1 项,然后是每个列表的第 2 项等吗?
  • 是的,订单是一项要求。列表的长度相同。

标签: c# loops tuples console-application


【解决方案1】:

当然,您可以将所有列表连接成objectstring 项的序列,但是这种连接不会使您的代码更具可读性。但是您可以创建简单的扩展方法,将任何序列的内容转储到控制台:

public static void Dump<T>(this IEnumerable<T> source)
{
    foreach(var item in source)
       Console.WriteLine(item);
}

你的代码看起来像(根本没有循环):

public void Print(Tuple<List<DateTime>, List<double>, List<string>> dataToPrint)
{
    dataToPrint.Item1.Dump();
    dataToPrint.Item2.Dump();
    dataToPrint.Item3.Dump();
}

我还会使用命名参数、自定义类型或值元组将这三个值传递给方法。

【讨论】:

    【解决方案2】:

    可以,但您必须确保所有列表的长度相同。
    你基本上可以这样做:

    for (var i = 0; i < dataToPrint.Item1.Length; i++)
    {
        Console.WriteLine(dataToPrint.Item1[i]);
        Console.WriteLine(dataToPrint.Item2[i]);
        Console.WriteLine(dataToPrint.Item3[i]);
    }
    

    【讨论】:

    • 这将以与原始代码不同的顺序打印。不确定这是否是一个问题
    • 我虽然这是 OP 想要的。但实际上,这与原始问题的输出不同。
    【解决方案3】:

    编辑:在日期时间列表上调用 ForEach(Console.WriteLine) 实际上不起作用,因为 Console.WriteLine 没有使用日期时间的特定覆盖,它只使用需要对象的覆盖。由于 List.ForEach 需要一个 Action 并且编写日期时间所需的 Console.WriteLine 方法实际上是一个 Action ,因此此代码不会编译,因此此答案不正确。不过我觉得看看它为什么不起作用很有趣,所以我把它留在这里

    我不确定为什么你的代码有问题。如果那是该方法的签名并且您无法更改它,那么对我来说这似乎是有效的。如果你出于某种原因真的想限制你的行代码,你可以这样做

    dataToPrint.Item1.ForEach(Console.WriteLine);
    dataToPrint.Item2.ForEach(Console.WriteLine);
    dataToPrint.Item3.ForEach(Console.WriteLine);
    

    其他人建议所有列表的 for 循环长度相同,但这将以与您描述的顺序不同的顺序打印出来。并将所有列表中的所有项目转换为对象,以便您可以联系列表可能会很昂贵,这要归功于将您的值类型(如 double)装箱。 编辑:我被告知,与写入控制台的性能相比,拳击可能可以忽略不计。但是我仍然认为将它们全部转换为对象不是最好的选择,但这只是我

    【讨论】:

    • 第一行给出以下错误:CS0123 No overload for 'Console.WriteLine(object)' matches delegate 'Action
    • 这是我在手机上写的。在我的笔记本电脑上让我检查一下我的语法,我会回复你
    • 嗯,他们说你每天都能学到新东西。 Console.WriteLine() 没有采用 DateTime 的特定重载,它解决了用户只采用对象的重载。由于我猜是 co/contra -variance 的一些问题, List.ForEach 需要一个 Action 并且编译器不喜欢你的 DateTime 列表调用了 ForEach 并且实际上是被传递了一个 Action 而不是 Action ...所以简而言之,我的答案不起作用,我将把它留在那里并编辑它,因为我认为它很有趣
    【解决方案4】:

    试试这个:

    foreach (var element in dataToPrint.Item1.Cast<object>().Concat(dataToPrint.Item2.Cast<object>()).Concat(dataToPrint.Item3.Cast<object>()))
    {
        Console.WriteLine(element);
    }
    

    【讨论】:

    • 根据这些列表的大小,装箱(和拆箱?)值类型会不会影响性能?
    • 我认为 Console.WriteLine 是最慢的部分 - 装箱和拆箱应该没那么重要。
    • 我不知道它特别昂贵。以后我会牢记这一点
    • 当您只需要一个值类型的字符串表示时,为什么还要装箱呢?将所有内容连接到IEnumerable&lt;string&gt;ToString 无论如何都会被调用,提前做。
    猜你喜欢
    • 1970-01-01
    • 2017-12-10
    • 1970-01-01
    • 2016-03-12
    • 2019-11-17
    • 1970-01-01
    • 2013-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多