列出与其他列表条件相关的操作

时间:2014-01-15 07:47:12

标签: c# linq list indexing

我有两个这样的列表:

public static List<List<List<double>>> listQ = new List<List<List<double>>>();
public static List<List<List<double>>> listVal = new List <List<List<double>>>();

enter image description here

2列表也有相同的大小。我想在listQ关系中对listVal进行一些操作:

  • 如果listVal的任何索引具有相同的值,我想在相同的索引中取平均listQ的值。

例如:

listVal[0][0][ 1] = listVal[0][0][2] = 3. 

所以,我希望listQ的索引相同。

(listQ[0][0][ 1] + listQ[0][0][2]) / 2 = (26.5 + 20.4) / 2 = 23.45. 

现在,每个索引都必须有23.45:

listQ[0][0][ 1] = 23.45

listQ[0][0][ 2] = 23.45

同样;

listVal[0][2][0] = listVal[0][2][2] = 1。因此,必须考虑listQ[0][2][0] and listQ[0][2][2]的平均值。

我该怎么做?

编辑:@Roman Izosimov和@Petko Petkov的解决方案正常运作。哪一个有更高的性能?你怎么看?

3 个答案:

答案 0 :(得分:4)

lulz的LINQ解决方案:)

List<List<List<double>>> listVal = new List<List<List<double>>>(){
    new List<List<double>>{
        new List<double>(){1,1,3},
        new List<double>(){2,1,2},
        new List<double>(){1,2,3}
    },
    new List<List<double>>{
        new List<double>(){2,1,3},
        new List<double>(){2,4,2},
        new List<double>(){3,1,3}
    },
    new List<List<double>>{
        new List<double>(){4,1,1},
        new List<double>(){4,2,1},
        new List<double>(){4,3,1}
    }
};
List<List<List<double>>> listQ = new List<List<List<double>>>(){
        new List<List<double>>{
        new List<double>(){3,7,4},
        new List<double>(){8,15,23},
        new List<double>(){11,13,17}
    },
    new List<List<double>>{
        new List<double>(){90,3,7},
        new List<double>(){5,7,12},
        new List<double>(){7,14,21}
    },
    new List<List<double>>{
        new List<double>(){32,4,1},
        new List<double>(){55,12,8},
        new List<double>(){3,5,8}
    }
};


//Linq awesomeness
var qry = listVal.SelectMany((l1, i0) =>
                l1.SelectMany((l2, i1) =>
                    l2.Select((ele, i2) =>
                        new { i0, i1, i2, gVal = ele, qVal = listQ[i0][i1][i2] })))
                .GroupBy(x => new { x.i0, x.i1, x.gVal }) // if you want to average across the innermost lists only 
                //.GroupBy(x => x.gVal)                   //if you want to average acreoss the whole data
                .SelectMany(x => x.Select(e => new { e.i0, e.i1, e.i2, avg = x.Average(y => y.qVal) }));
foreach (var e in qry)
{
    listQ[e.i0][e.i1][e.i2] = e.avg;
}

答案 1 :(得分:3)

您的问题类似于计算列表中元素的频率 您可以使用Dictionary<double,List<int[]> double键是listVal中的值,List<int[]>将该值的位置存储在listVal中。

这是我的示例代码:

//we store list of indices with the same value in a dictionary
Dictionary<double, List<int[]>> dictionary = new Dictionary<double, List<int[]>>();

//loop over listVal
for (int i = 0; i < listVal.Count; i++)
    for (int j = 0; j < listVal[i].Count; j++)
        for (int k = 0; k < listVal[i][j].Count; k++)
        {
            if (!dictionary.ContainsKey(listVal[i][j][k]))
            {
                //if the dictionary doesn't have value listVal[i][j][k] 
                //then add the value as key with the value's current index
                dictionary.Add(listVal[i][j][k], new List<int[]> { new int[] { i, j, k } });
            }
            else
            {
                //add more index of the same value to the index list
                dictionary[listVal[i][j][k]].Add(new int[] { i, j, k });
            }
        }

foreach (var entry in dictionary)
{
    //get list of all position having the same value
    List<int[]> indices = entry.Value;

    //do your process on listQ
    //sum values in listQ
    double sum = 0;
    foreach (var index in indices)
    {
        sum += listQ[index[0]][index[1]][index[2]];
    }
    //calculate average value
    double average = sum / indices.Count;

    //assign back to litsQ
    foreach (var index in indices)
    {
        listQ[index[0]][index[1]][index[2]]  = average;
    }


}

答案 2 :(得分:3)

在我的解决方案中,您可以在List<double>listQ listVal中包含任意数量的元素,但在这两个列表中,元素数量相同。

算法:

for (var i1 = 0; i1 < listVal.Count; i1++)
            for (var i2 = 0; i2 < listVal[i1].Count; i2++)
            {
                var alreadyInList = new Dictionary<double, List<Tuple<int, int, int>>>();
                for (var d = 0; d < listVal[i1][i2].Count; d++)
                {
                    var decVal = listVal[i1][i2][d];
                    if (!alreadyInList.ContainsKey(decVal))
                    {
                        alreadyInList.Add(decVal, new List<Tuple<int, int, int>>());
                        continue;
                    }
                    var firstMatchElIndex = listVal[i1][i2].IndexOf(decVal);
                    if (alreadyInList[decVal].All(x => x.Item3 != firstMatchElIndex))
                        alreadyInList[decVal].Add(new Tuple<int, int, int>(i1, i2, firstMatchElIndex));

                    alreadyInList[decVal].Add(new Tuple<int, int, int>(i1, i2, d));
                }

                SetListQ(listQ, alreadyInList.Where(x => x.Value.Count > 1).Select(x => x.Value));
            }

private void SetListQ(List<List<List<double>>> listQ, IEnumerable<List<Tuple<int, int, int>>> matches)
    {
        foreach (var match in matches)
        {
            var sum = match.Sum(tuple => listQ[tuple.Item1][tuple.Item2][tuple.Item3]);
            var avg = sum / match.Count;
            foreach (var tuple in match)
                listQ[tuple.Item1][tuple.Item2][tuple.Item3] = avg;
        }
    }

并检查:

Console.WriteLine("listQ[0][0][0] = {0}", listQ[0][0][0]);
Console.WriteLine("listQ[0][0][1] = {0}", listQ[0][0][1]);
Console.WriteLine("listQ[0][0][2] = {0}", listQ[0][0][2]);
//....

使用您的数据:

var listQ = new List<List<List<double>>>
        {
            new List<List<double>>
            {
                new List<double>{20.9, 26.5, 20.4},
                new List<double>{18.3, 19.7, 22.2},
                new List<double>{12.7, 20.6, 25.6},
                new List<double>{17.1},
                new List<double>{17.3},
                new List<double>{16.9}
            }
        };

        var listVal = new List<List<List<double>>>
        {
            new List<List<double>>
            {
                new List<double>{1, 3, 3},
                new List<double>{1, 3, 3},
                new List<double>{1, 3, 1},
                new List<double>{1},
                new List<double>{3},
                new List<double>{3}
            }
        };

我们在控制台中:

listQ[0][0][0] = 20.9
listQ[0][0][1] = 23.45
listQ[0][0][2] = 23.45
listQ[0][1][0] = 18.3
listQ[0][1][1] = 20.95
listQ[0][1][2] = 20.95
listQ[0][2][0] = 19.15
listQ[0][2][1] = 20.6
listQ[0][2][2] = 19.15

例如,我添加了一些额外的数据:

var listQ = new List<List<List<double>>>
        {
            new List<List<double>>
            {
                new List<double>{20.9, 26.5, 20.4, 10.0},
                new List<double>{18.3, 19.7, 22.2, 12.22},
                new List<double>{12.7, 20.6, 25.6, 20.6},
                new List<double>{17.1},
                new List<double>{17.3},
                new List<double>{16.9}
            }
        };

        var listVal = new List<List<List<double>>>
        {
            new List<List<double>>
            {
                new List<double>{1, 3, 3, 1},
                new List<double>{1, 3, 3, 3},
                new List<double>{1, 3, 1, 2},
                new List<double>{1},
                new List<double>{3},
                new List<double>{3}
            }
        };

处理完毕后我们有:

listQ[0][0][0] = 15.45
listQ[0][0][1] = 23.45
listQ[0][0][2] = 23.45
listQ[0][0][3] = 15.45
listQ[0][1][0] = 18.3
listQ[0][1][1] = 18.04
listQ[0][1][2] = 18.04
listQ[0][1][3] = 18.04
listQ[0][2][0] = 19.15
listQ[0][2][1] = 20.6
listQ[0][2][2] = 19.15
listQ[0][2][3] = 20.6

这不是一个很好的解决方案,但它可以工作并使用最少的迭代次数。我希望这个解决方案能够解决你的任务。