I have two lists like these:
public static List<List<List<double>>> listQ = new List<List<List<double>>>();
public static List<List<List<double>>> listVal = new List <List<List<double>>>();
2 list also have same size. I want some operations in listQ relation to listVal:
For example:
listVal[0][0][ 1] = listVal[0][0][2] = 3.
So, I want listQ's same indexes be same.
(listQ[0][0][ 1] + listQ[0][0][2]) / 2 = (26.5 + 20.4) / 2 = 23.45.
Now, each these indexes must have 23.45 :
listQ[0][0][ 1] = 23.45
listQ[0][0][ 2] = 23.45
Likewise;
listVal[0][2][0] = listVal[0][2][2] = 1
. Therefore listQ[0][2][0] and listQ[0][2][2]
's average must be taken.
How can I do this?
EDIT : @Roman Izosimov 's and @Petko Petkov 's solutions are working correctly. Which one has higher performance? What do you think?
LINQ solutions for lulz :)
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;
}
Your problem is similar to count the frequences of elements in a list.
Your can use a Dictionary<double,List<int[]>
with the double
key is value in listVal, and List<int[]>
stores the positions of that value in listVal.
Here my sample code:
//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;
}
}
In my solution you can have any numbers of elements in List<double>
in listQ
and listVal
, but in both lists elements count mus be same.
Algorithm:
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;
}
}
And check:
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]);
//....
Using your data:
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}
}
};
We have in Console:
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
For example I added some additional data:
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}
}
};
After processing we have:
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
This is not whery nice solution but it works and use minimum iterations count. I hope this solution will solve your task.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With