按距离对位于同一位置的服务器列表进行排序
本文关键字:列表 服务器 排序 位置 距离 于同一 | 更新日期: 2023-09-27 18:07:03
我有一个服务器列表(标题,负载,距离)初始列表已按距离分组。
- LOC1 S1: Load NULL - 3km
- LOC1 S2:负载0.1 - 3km
- LOC1 S3:负载0.6 - 3km
- LOC1 S4:负荷0.2 - 3km
- LOC2 S1:负载0.7 - 1km
- LOC2 S2:负载0.1 - 1km
- LOC2 S3:负载0.2 - 1km
- LOC3 S1:负载0.1 - 2km
我正试图写一个Linq查询,做以下事情:对于每个按位置分组的服务器列表,取加载最少的项(带null的加载项应该被忽略并推到输出列表的后面)。然后对每组中第二个加载最少的项目重复相同的操作。如果我们应用这个逻辑,那么我们应该得到:
每组按距离排序的第一个最小加载项:
第一步是有一个按距离分组的有序列表。因为距离是每组的关键。
From first group first least
- Loc 2 S2:负载0.1 - 1km
下一组是Loc 3
- Loc 3 S1:负载0.1 - 2km
下一组为Loc 1
- Loc 1 S2:负载0.1 - 3km
From first group From second least loaded
- LOC2 S3:负载0.2 - 2km
- LOC1 S4:负载0.2 -3km
注意这里没有位置3,因为它没有第二个加载0.2
最后第三个最少装载的项目是…
- LOC2 S1:负载0.7 - 1km
- LOC 1 S3:负载0.6 3km
如果我们把这些组合在一起,我们有:
1组:
Loc 2 S2:负载0.1 - 1km
Loc 3 S1:负载0.1 - 2km
Loc 1 S2:负载0.1 - 3km
2组
LOC2 S3:负载0.2 - 2km
LOC1 S4:负载0.2 -3km
第三组
- LOC2 S1:负载0.7 - 1km
- LOC 1 S3:负载0.6 3km
最后将这些加起来,按照每组的距离和负载进行排序:
LOC 2 S2:负载0.1 - 1km
LOC 3 S1:负载0.1 - 2km
LOC 1 S2:负载0.1 - 3km
LOC 2 S3:负载0.2 - 2km
LOC 1 S4:负载0.2 - 3km
LOC 2 S1:负载0.7 - 1km
LOC 1 S3:负载0.6 - 3km
我已经尝试了以下同步:
var orderedbyLoad = servers.OrderBy(t=>t.Load);
var groupByDistance = orderedbyLoad.GroupBy(a=>a.Distance,s=>s);
这应该给出一个按距离排序的组,以及每个组中按负载排序的服务器列表。
下一步是我有问题的地方。我想对每个组使用某种取逻辑,然后循环遍历每个组中的下一个加载项。这些需要都项目到一个平面列表,如上所示,尊重距离,然后加载顺序,但我不确定如何用linq做到这一点?
问题出在最后两项。如果我运行你的查询,我会得到var groupedByDistance =服务器。其中(x => x. load != null)。order (x => x. load)。then (x => x. distance);
:
LOC 2 S2 Load 0.1 Dist 1
LOC 3 S1 Load 0.1 Dist 2
LOC 1 S2 Load 0.1 Dist 3
LOC 2 S3 Load 0.2 Dist 1
LOC 1 S4 Load 0.2 Dist 3
LOC 1 S3 Load 0.6 Dist 3
LOC 2 S1 Load 0.7 Dist 1
由于距离应该是第一位的,那么load Loc2 S1 load 0.7应该在Loc1 S3 load 0.6之前@shameel
我正在检查我的pseudo,因此我想出了我的实现:
static IEnumerable<Server> Zip(IEnumerable<IEnumerable<Server>> groups)
{
bool repeat = true;
int i=0;
while(repeat)
{
repeat = false;
foreach (var grp in groups)
{
var element = grp.Skip(i).ElementAtOrDefault(0);
if (element != null)
{
repeat = true;
yield return element;
}
}
i++;
}
}
与你的唯一不同是当加上我认为它应该是一样的。关于
Shameel
有趣的问题。我不知道这是否可以以一种优雅的方式完成,但是您可以将groupByDistance
传递给这样的方法:
IEnumerable<Server> Zip(IEnumerable<IEnumerable<Server>> groups)
{
bool cont;
int i = 0;
do
{
cont = false;
foreach (var grp in groups)
{
var element = grp.Skip(i).FirstOrDefault();
if (element != null)
{
cont = true;
yield return element;
}
}
++i;
} while (cont);
}
将返回一个IEnumerable
,因此如果需要,它可以在进一步的LINQ查询中使用。它还具有延迟枚举的特性。但是——它绝对不优雅。
我的完整的沙盒来尝试这个,//option2是你的选择:
using System.Collections.Generic;
using System.Linq;
namespace LinqTest01
{
class Program
{
static void Main(string[] args)
{
List<Server> servers = new List<Server>{
new Server(){ load = null, distance = 3 },
new Server(){ load = 0.1, distance = 3 },
new Server(){ load = 0.6, distance = 3 },
new Server(){ load = 0.2, distance = 3 },
new Server(){ load = 0.7, distance = 1 },
new Server(){ load = 0.1, distance = 1 },
new Server(){ load = 0.2, distance = 1 },
new Server(){ load = 0.1, distance = 2 },
};
// option 1
var sorted = from server in servers orderby server.load where server.load != null select server;
var groups = from server in sorted
group server by server.distance into bydistance
orderby bydistance.Key
select bydistance
;
var final1 = Zip(groups);
// option 2
var orderedbyLoad = servers.OrderBy(t => t.load);
var groupByDistance = orderedbyLoad.GroupBy(a => a.distance, s => s);
var final2 = Zip(groups);
}
static IEnumerable<Server> Zip(IEnumerable<IEnumerable<Server>> groups)
{
bool cont;
int i = 0;
do
{
cont = false;
foreach (var grp in groups)
{
var element = grp.Skip(i).FirstOrDefault();
if (element != null)
{
cont = true;
yield return element;
}
}
++i;
} while (cont);
}
}
class Server
{
public double? load;
public int distance;
}
}
你为什么不试试这样做呢?
作为servers
的原始(非分组)服务器列表:
servers.Where(x => x.Load != null).OrderBy(x => x.Load).ThenBy(x => x.Distance)
如果我没理解错的话,这应该会给你一个列表,按照最近的距离排序,然后是最小的负载。
如果你想把"null loads"添加到列表的末尾:
servers.Where(x => x.Load != null).OrderBy(x => x.Load).ThenBy(x => x.Distance).Concat(servers.Where(x => x.Load == null))
这是你想要达到的目标吗?
编辑:那一个没有尊重组之间的确切顺序。为了实现您应该"手动"遍历每个组,使用此代码和您的测试用例,我得到了预期的结果:
List<Server> serversList = new List<Server>();
serversList.Add(new Server { Name = "S1", Location = "LOC1", Distance = 3, Load = null });
serversList.Add(new Server { Name = "S2", Location = "LOC1", Distance = 3, Load = 1 });
serversList.Add(new Server { Name = "S3", Location = "LOC1", Distance = 3, Load = 6 });
serversList.Add(new Server { Name = "S4", Location = "LOC1", Distance = 3, Load = 2 });
serversList.Add(new Server { Name = "S1", Location = "LOC2", Distance = 1, Load = 7 });
serversList.Add(new Server { Name = "S2", Location = "LOC2", Distance = 1, Load = 1 });
serversList.Add(new Server { Name = "S3", Location = "LOC2", Distance = 1, Load = 2 });
serversList.Add(new Server { Name = "S1", Location = "LOC3", Distance = 2, Load = 1 });
List<Server> orderedList = new List<Server>();
var serversByDistance = serversList.Where(x => x.Load != null)
.OrderBy(x => x.Distance)
.GroupBy(x => x.Distance)
.ToDictionary(x => x.Key, x => x.OrderBy(s => s.Load).ToList());
for (int i = 0; i < serversByDistance.Values.Max(x => x.Count); i++)
{
foreach (var key in serversByDistance.Keys)
{
var element = serversByDistance[key].ElementAtOrDefault(i);
if (element != null)
orderedList.Add(element);
}
}
如果需要,可以将null结果添加到orderedList
。
(注意:为了简单起见,我使用int类型进行测试…P)