在我们公司,有数千(!)辆汽车。每辆车都有一个GPS设备,定期发送(cycle
)其位置。
因此每个Cycle
包含:
List<Cars>
(发送位置的车辆 - 对应CycleNum
)CycleNum
这是周期号 CycleNum
由服务器决定。
例如,在CycleNum=1
中,有4辆车发送了他们的位置:
我使用的类(简化)
static int TotalCycles=0;
class Car
{
public int CarId;
public int Location ;
}
class Cycle
{
public int CycleNum;
public List<Car> Cars;
public Cycle ()
{
CycleNum=(++TotalCycles);
}
}
让我们填写一些数据:
List<Cycle> LstCyclces = new List<Cycle>();
Cycle cycle =null;
cycle = new Cycle();//cycle 1
cycle.Cars = new List<Car>();
cycle.Cars.Add(new Car {CarId=1 , Location=40});
cycle.Cars.Add(new Car {CarId=2 , Location=21});
cycle.Cars.Add(new Car {CarId=3 , Location=5});
cycle.Cars.Add(new Car {CarId=4 , Location=15});
LstCyclces.Add(cycle);
cycle = new Cycle();//cycle2
cycle.Cars = new List<Car>();
cycle.Cars.Add(new Car {CarId=1 , Location=40}); //same location
cycle.Cars.Add(new Car {CarId=2 , Location=57});//changed location
cycle.Cars.Add(new Car {CarId=3 , Location=100});//changed location
cycle.Cars.Add(new Car {CarId=4 , Location=7});//changed location
cycle.Cars.Add(new Car {CarId=7 , Location=2});//new attended ( vs previous cycle)
LstCyclces.Add(cycle);
cycle = new Cycle();//cycle3
cycle.Cars = new List<Car>();
cycle.Cars.Add(new Car {CarId=1 , Location=40}); //same
cycle.Cars.Add(new Car {CarId=2 , Location=5});//changed Location
cycle.Cars.Add(new Car {CarId=4 , Location=1});//changed Location
cycle.Cars.Add(new Car {CarId=9 , Location=7});//new attended ( vs previous cycle)
LstCyclces.Add(cycle);
可视化:
如你所见:
问题
我被要求:
对于特定的给定周期数 - 查找上一周期中预期的所有汽车:
("new Location" - "previous Location") < abs(40)
从结果集中,找到所有车辆PAIRS:
(Car_A.Location - Car_B.Location) < abs(65)
简而言之 - 我需要所有提供上一周期信息的汽车,而且他们离他们以前的位置也不远,最后 - 从这些车 - 我需要知道哪些车彼此靠近
非常重要:我无法只检查当前的位置,因为我们还需要确保汽车离他们之前的位置不远。
所以根据图片:cycleNum=2
:
在上一个周期(1)中预测的汽车是汽车:1,2,3,4。
从那个结果:那些离他们以前的位置不远的汽车:
("new Location" - "previous Location") < abs(40)
是汽车:1,2,4。
从那个结果我需要找到现在彼此相距不远的所有汽车对:
(Car_A.Location - Car_B.Location) < abs(65)
:
所以结果应该是IEnumerable :(格式无关紧要)
{ Car1 , Car2 , distance=17}
//这两辆车之间的距离< 65 { Car1 , Car4 , distance=33}
//这两辆车之间的距离< 65 { Car2 , Car4 , distance=50}
//这两辆车之间的距离< 65 //我不介意拥有所有排列( {car1 car2} , {car2 car1} )
我尝试了什么:
var cycleToCheck=2;
//get all cars from desired cycle
var requestedCycleCars = LstCyclces.Where(c=>c.CycleNum==cycleToCheck).SelectMany(c=>c.Cars);
//get all cars from previous cycle
var previousCycleCars = LstCyclces.Where(c=>c.CycleNum==cycleToCheck-1).SelectMany(c=>c.Cars);
//intersec between those
var MyWrongIntersect =requestedCycleCars.Intersect(previousCycleCars,new MyEqualityComparer());
但是我只从当前周期获得汽车,而不是从前一个周期获得汽车。此外 - 我需要从当前周期和前一个周期(不重复)引用汽车 - 用于计算。
另外我认为我使用SelectMany
走错路径,这可能是最快的(c#,plinq?)。我希望它可以在一个查询中。
有任何帮助吗?
nb,当然我可以分阶段完成,但重申,或者ToList()对我来说是不好的方法。我希望有一个单一的plinq查询
发布的解决方案在逻辑上可以正常工作,但不是很有效。
2个周期,每个周期有10,000辆车:&gt; 9分钟! :
http://i.stack.imgur.com/mjLvG.jpg
我该如何改进?(asparallel并不起作用)
答案 0 :(得分:5)
嗯,就效率而言,
假设有很多这样的对, From that result I need to find all pairs of car who are now not far from each other :
是性能相当的杀手。朴素算法至少会运行n^2
。您希望使用SQL空间类型,这将使查询更有效。
如果你不愿意这样做/不能这样做,那么你可以做很多事情来提高表现,我愿意猜测。
下一个代码将在Cars
之间进行有效的连接。将CarId
编入索引非常重要。在我们找到所有对c.Distance <40
后,我们将在客户端的计算机上进行最终处理,因为这样我们就可以自己有效地处理已排序的汽车。
var cycleNum = 2;
var curCycleCars = LstCyclces[cycleNum - 1].Cars;
var prevCycleCars = LstCyclces[cycleNum - 2].Cars;
var cars = curCycleCars.Join(prevCycleCars,
p => p.CarId,
y => y.CarId,
(f1, f2) => new {
Car = f1,
Distance = f1.Location - f2.Location
})
.Where(c => c.Distance < 40)
.Select(c => c.Car)
.OrderBy(car => car.Location)
.ToList();
var carPairs = new CarPairList[cars.Count()];
for(var i = 0; i < cars.Count; i++)
{
var curCar = cars[i];
var curStartIndex = i + 1;
if(i > 0)
{
var previousCarPair = carPairs[i - 1];
if(previousCarPair!=null)
{
curStartIndex = previousCarPair.EndIndex;
}
}
int j;
for(j = curStartIndex; j < cars.Count; j++)
{
var dis = cars[j].Location - curCar.Location;
if(dis >= 65) break;
}
var startIndex = i + 1;
var endIndex = j - 1;
if(endIndex >= startIndex)
{
carPairs[i] = new CarPairList(curCar,
startIndex, endIndex);
}
}
foreach(var carPair in carPairs.Where(x => x!=null)){
Console.WriteLine("Car " + carPair.Car.CarId);
Console.WriteLine("Cars near the distance: ");
for(var i = carPair.StartIndex; i <= carPair.EndIndex; i++){
Console.WriteLine("\t - {0}, distance {1}",
cars[i].CarId,
cars[i].Location - carPair.Car.Location);
}
Console.WriteLine();
}
class CarPairList
{
public readonly Car Car;
public readonly int StartIndex;
public readonly int EndIndex;
public CarPairList(Car car,
int startIndex,
int endIndex){
Car = car;
StartIndex = startIndex;
EndIndex = endIndex;
}
}
答案 1 :(得分:2)
这个代码
var cycleToCheck = 2;
var query = LstCyclces.FirstOrDefault(c => c.CycleNum == cycleToCheck).Cars
.Where(c => LstCyclces.FirstOrDefault(p => p.CycleNum == cycleToCheck - 1).Cars
.Any(ca => ca.CarId == c.CarId && Math.Abs(c.Location - ca.Location) < 40));
var result = query.SelectMany(t1 => query.Select(t2 => Tuple.Create(t1, t2)))
.Where(x => Math.Abs(x.Item1.Location - x.Item2.Location) < 65 && x.Item1.CarId < x.Item2.CarId);
foreach (var r in result)
{
Console.WriteLine("{0} - {1}", r.Item1.CarId, r.Item2.CarId);
}
Here正在运行样本
<强>被修改强>