简体   繁体   English

如何使用 LINQ 将多级元组列表拆分为多级值列表?

[英]How to split multi-level list of tuples into multi-level lists of values using LINQ?

I have a List<List<Tuple<int, int, int>>> variable and I want to split it to three List<List<int>> s.我有一个List<List<Tuple<int, int, int>>>变量,我想将它拆分为三个List<List<int>> s。 I already can enumerate the list three time like this:我已经可以像这样枚举列表三次:

List<List<Tuple<int, int, int>>> tuples = ...
List<List<int>> a = tuples.Select(x => x.Select(y => y.Item1).ToList()).ToList();
List<List<int>> b = tuples.Select(x => x.Select(y => y.Item2).ToList()).ToList();
List<List<int>> c = tuples.Select(x => x.Select(y => y.Item3).ToList()).ToList();

But, can I make all three lists at once using LINQ?但是,我可以使用 LINQ 一次制作所有三个列表吗? Something like:就像是:

Tuple<List<List<int>>, List<List<int>>, List<List<int>>> splitted = tuples.Magic(...);

Edit: (This is added after tymtam and Mong Zhu posted their answers)编辑:(这是在 tymtam 和 Mong Zhu 发布答案后添加的)

To be more clear, later when I said "at once", I was concerning performance.更清楚地说,后来当我说“立即”时,我指的是性能。 I don't really care about actual type of outcome and I don't have obsession with doing it in single line.我并不真正关心结果的实际类型,我也不痴迷于单行。

Performance-wise Comparison:性能比较:

This is my code to compare splitting 1000 lists of 1000 tuples, (50 calls, 4000 sample/s):这是我比较拆分 1000 个元组的 1000 个列表的代码(50 个调用,4000 个样本/秒):

private void Split_Loop(List<List<Tuple<int, int, int>>> tuples)
{
    List<List<int>> a = new List<List<int>>(tuples.Count);
    List<List<int>> b = new List<List<int>>(tuples.Count);
    List<List<int>> c = new List<List<int>>(tuples.Count);
    for (int i = 0; i < tuples.Count; i++)
    {
        int n = tuples[i].Count;
        List<int> l1 = new List<int>(n);
        a.Add(l1);
        List<int> l2 = new List<int>(n);
        b.Add(l2);
        List<int> l3 = new List<int>(n);
        c.Add(l3);

        for (int j = 0; j < n; j++)
        {
            l1.Add(tuples[i][j].Item1);
            l2.Add(tuples[i][j].Item2);
            l3.Add(tuples[i][j].Item3);
        }
    }
}
private void Split_Linq3(List<List<Tuple<int, int, int>>> tuples)
{
    List<List<int>> a = tuples.Select(x => x.Select(y => y.Item1).ToList()).ToList();
    List<List<int>> b = tuples.Select(x => x.Select(y => y.Item2).ToList()).ToList();
    List<List<int>> c = tuples.Select(x => x.Select(y => y.Item3).ToList()).ToList();
}
private void Split_tymtam(List<List<Tuple<int, int, int>>> tuples)
{
    IEnumerable<List<List<int>>> a = new Func<Tuple<int, int, int>, int>[]
        { t => t.Item1, t => t.Item2, t => t.Item3 }.
            Select(f => tuples.Select(x => x.Select(f).ToList()).ToList());
    List<List<List<int>>> b = a.ToList();
}
private void Split_Mong(List<List<Tuple<int, int, int>>> tuples)
{
    Func<List<List<Tuple<int, int, int>>>, Func<Tuple<int, int, int>, int>, List<List<int>>> selectorGen = (x, t) => x.Select(y => y.Select(t).ToList()).ToList();
    Tuple<List<List<int>>, List<List<int>>, List<List<int>>> splitted = Tuple.Create(
            selectorGen(tuples, t => t.Item1),
            selectorGen(tuples, t => t.Item2),
            selectorGen(tuples, t => t.Item3));
}
private void button3_Click(object sender, EventArgs e)
{
    int outer = 1000;
    int inner = 1000;
    List<List<Tuple<int, int, int>>> tuples = new List<List<Tuple<int, int, int>>>(outer);
    for (int i = 0; i < outer; i++)
    {
        List<Tuple<int, int, int>> list = new List<Tuple<int, int, int>>(inner);
        tuples.Add(list);
        for (int j = 0; j < inner; j++)
        {
            Tuple<int, int, int> tuple = new Tuple<int, int, int>(i + j + 1, i + j + 2, i + j + 3);
            list.Add(tuple);
        }
    }
    for (int i = 0; i < 50; i++)
    {
        Split_Loop(tuples);
        Split_Linq3(tuples);
        Split_tymtam(tuples);
        Split_Mong(tuples);
    }
}

and this is the results:这是结果: 在此处输入图像描述

This is the best I can do:这是我能做的最好的:

IEnumerable<List<List<int>>> myLists = new Func<Tuple<int, int, int>, int>[] 
            { t => t.Item1, t => t.Item2, t => t.Item3 }
           .Select(f => tuples.Select(x => x.Select(f).ToList()).ToList());

You could define a selector function, that takes your tuples collection and a selector for the tuple item as input and returns a List<List<int>> :您可以定义一个选择器 function,它将您的tuples集合和元组项的选择器作为输入并返回一个List<List<int>>

Func<List<List<Tuple<int, int, int>>>, Func<Tuple<int, int, int>, int>, List<List<int>>> selectorGen = (x,t) => x.Select(y => y.Select(t).ToList()).ToList();

now you can apply this selector to extract the individual items into the corresponding lists while you create a tuple containing the resulting collections:现在您可以应用此选择器将各个项目提取到相应的列表中,同时创建一个包含生成的 collections 的元组:

Tuple<List<List<int>>, List<List<int>>, List<List<int>>> splitted = Tuple.Create(
                    selectorGen(tuples, t => t.Item1),
                    selectorGen(tuples, t => t.Item2),
                    selectorGen(tuples, t => t.Item3));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM