我有一个List<List<Tuple<int, int, double>>
类型的列表。
从语义上讲,它的工作原理如下:
double
)。Sum(t => t.Item3)
描述了轨迹上的能量(离散值的积分)。现在我想找到哪个子列表能量最少。我尝试了下面的代码,但这给了我最低的值,而我希望 list 本身具有最低的值。
var minimum_path = all_paths.Min(c => c.Sum(p => p.Item3));
^___ "var" is of type double, should be List<Tuple<...>>
答案 0 :(得分:3)
您必须按总和订购:
List<Tuple<int, int, double>> minList = all_paths
.OrderBy(l => l.Sum(t => t.Item3))
.First();
如果您想获得总体上包含最小Item3
的列表:
List<Tuple<int, int, double>> minList = all_paths
.OrderBy(l => l.Min(t => t.Item3))
.First();
您也可以按此分组以查找具有此值的其他列表:
List<List<Tuple<int, int, double>>> allMinLists = all_paths
.GroupBy(l => l.Sum(t => t.Item3))
.OrderBy(g => g.Key)
.First()
.ToList();
答案 1 :(得分:2)
这里有一个O(n)
解决方案(列表数量)只迭代父列表一次:
var minList = all_paths
.Aggregate((x, y) => x.Sum(i => i.Item3) < y.Sum(i => i.Item3) ? x : y);
答案 2 :(得分:1)
Orderby有O(n ^ 2)的复杂度,所以我猜这个变体应该更好,因为3 {n次传递和Sum()
函数的单次评估而不是OrderBy
处理中每个比较的计算:
var pathsWithEnergy = all_paths.Select(c => new {Value = c, Energy = c.Sum(p => p.Item3)}).ToList();
var minimum_energy = pathsWithEnergy.Min(x => x.Energy);
var minimum_path = pathsWithEnergy.Find(x => x.Energy == minimum_energy);
如果列表很大,那么更好的方法是结合我的灵魂和@Rawling的
var minList = all_paths.Select(c => new {Value = c, Energy = c.Sum(p => p.Item3)})
.Aggregate((x, y) => x.Energy < y.Energy ? x : y).Value;
在我的工作台上,这个解决方案比使用&#34; brute-aggregate&#34;的原始解决方案快2倍。
class Program
{
static void Main()
{
var all_paths = new List<List<Tuple<int, int, double>>>();
const int n = 4000;
for (int i = 0; i < n; i++)
{
var tuples = new List<Tuple<int, int, double>>();
for (int j = 0; j < n; j++)
{
tuples.Add(new Tuple<int, int, double>(i, j, (n + i)*j));
}
all_paths.Add(tuples);
}
var sw = Stopwatch.StartNew();
var minList = MinList1(all_paths);
sw.Stop();
Console.WriteLine("{0} - {1}", minList[0], sw.Elapsed);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
var sw2 = Stopwatch.StartNew();
var minList2 = MinList2(all_paths);
sw2.Stop();
Console.WriteLine("{0} - {1}", minList2[0], sw2.Elapsed);
}
private static List<Tuple<int, int, double>> MinList1(List<List<Tuple<int, int, double>>> all_paths)
{
return all_paths.Select(c => new {Value = c, Energy = c.Sum(p => p.Item3)})
.Aggregate((x, y) => x.Energy < y.Energy ? x : y).Value;
}
private static List<Tuple<int, int, double>> MinList2(List<List<Tuple<int, int, double>>> all_paths)
{
return all_paths.Aggregate((x, y) => x.Sum(i => i.Item3) < y.Sum(i => i.Item3) ? x : y);
}
}
答案 3 :(得分:1)
如果您的应用对性能敏感,我建议您忘记LINQ(Sum
:)除外。
private static List<Tuple<int, int, double>> GetMinimumPath(List<List<Tuple<int, int, double>>> all_paths)
{
double minSum = double.MaxValue;
List<Tuple<int, int, double>> minSumPath = null;
foreach (var path in all_paths)
{
double curSum = path.Sum(t => t.Item3);
if (curSum < minSum)
{
minSum = curSum;
minSumPath = path;
}
}
return minSumPath;
}
或者,您可以实现通用MinBy(morelinq source)并将其用作:
var minimum_path = all_paths.MinBy(path => path.Sum(t => t.Item3));