遍历元组中的项

5

我有一个带有三个循环的方法:

    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);
        }
    }

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


更改类型是否存在问题? - EpicKip
1
你为什么要在这里使用 Tuple?如果所有的列表长度都相同,那么无论如何,请使用 List<Tuple<...>>,如果不是,则只需实现一个构建器方法来打印列表,并调用它三次即可。 - InBetween
这正是我在InBetween所想的,但它们可能长度不同。 - EpicKip
它打印的顺序是必需的吗?即第一个列表中的所有项目,然后是第二个列表中的所有项目等。还是可以先有每个列表的第1项,然后是每个列表的第2项等? - Dave
是的,顺序是必需的。这些列表具有相同的长度。 - Chris
4个回答

7

当然,你可以将所有列表连接成一个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();
}

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

1

是的,但您必须确保所有列表具有相同的长度。
您可以基本上执行以下操作:

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

这将以与原始代码不同的顺序打印。不确定是否存在问题。 - Dave
我以为这就是 OP 想要的。但实际上,这将不会产生与原始问题相同的输出。 - Jerodev

1
编辑:在日期时间列表上调用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“Console.WriteLine(object)”的重载不匹配委托“Action<DateTime>”。 - Chris
我用手机写的。等到我在笔记本电脑上检查语法后,我会回复你的。 - Dave
他们说每天都学到了新东西。Console.WriteLine()没有特定的重载来接收一个DateTime,它会解析为仅接收对象的重载。由于我猜测存在某些与协变/逆变有关的问题,List<T>.ForEach需要一个Action<T>,编译器不喜欢在DateTime列表上调用ForEach并且实际上传递的是Action<object>而不是Action<DateTime>...因此简而言之,我的答案不起作用,但我会将其留在那里并进行编辑,因为我认为它非常有趣。 - Dave

0

试试这个:

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

根据这些列表的大小,这样做是否会因为值类型的装箱和拆箱而影响性能? - Dave
我认为Console.WriteLine是最慢的部分 - 装箱和拆箱不应该有太大影响。 - Tom Söhne
我不知道它特别昂贵。将来我会记住的。 - Dave
1
为什么你需要将值类型装箱,当你只需要它的字符串表示?将所有内容连接成 IEnumerable<string>ToString 方法最终也会被调用,提前完成这个操作。 - InBetween

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接