分类排序优化
本文关键字:优化 排序 分类 | 更新日期: 2023-09-27 18:28:14
问题:将项(T)排序到bucket(ConcurrentBag)中的最佳方式是什么?
好吧,所以我还没有上算法课,所以我不确定我遇到的问题的最佳方法。
前提条件:
- 每个bucket都有一个唯一的标识符(在每个sBucket中)
- 每个sBucket都有一个唯一的标识符
- 每个项目都有一个唯一的标识符
- 每个项目都有一个与它所在的bucket相对应的属性(bucketId)属于
- 每个项目都有一个属性(sBucketId),对应于它属于superBucket
- Bucket和sBucket id是唯一的
- 我有一个ConcurrentBag,里面有我想分类的项目水桶
- 有几百件物品
- 有几十个水桶
- 有3个超级铲斗,其中包含铲斗
- 每个超级bucket包含相同的bucket,但有不同的bucket桶中的项目
我目前正在通过对项目集合的Parallel.foreach循环使用暴力,使用linq将项目的bucketId与每个单独的bucket进行比较。这是难以置信的缓慢和繁琐,所以我想找到一个更好的方法。
我考虑过根据它们的超级Bucket然后Bucket对项目进行排序,然后遍历每个超级Bucket->Bucket来插入项目。这应该是我走的路吗?
感谢您提供的任何帮助。
当前代码示例
ConcurrentBag<Item> items ...
List<SuperBuckets> ListOfSuperBuckets ...
Parallel.ForEach(items, item =>
{
ListOfSuperBuckets
.Where(sBucket => sBucket.id == item.sBucketId)
.First()
.buckets
.Where(bucket => bucket.id == item.bucketId)
.First()
.items
.Add(item);
});
我不会对此使用并行性,但有很多选项。
var groupedBySBucket = ListOfSuperBuckets
.GroupJoin(items, a => a.id, b => b.sBucketId, (a,b) => new
{
sBucket = a,
buckets = a.buckets
.GroupJoin(b, c => c.id, x => x.bucketId, (c, x) => new
{
bucket = c,
items = x
});
});
foreach (var g in groupedBySBucket)
{
// We benefit here from that the collection types are passed by reference.
foreach (var b in g.buckets)
{
b.bucket.AddRange(b.items);
}
}
或者,如果这对你来说太多的代码,这是可以比较的。
var groupedByBucket = ListOfSuperBuckets
.SelectMany(c => c.buckets, (a,b) => new { sBucketId = a.id, bucket = b })
.GroupJoin(items, a => new { a.sBucketId, bucketId = a.bucket.id }, b => new { b.sBucketId, b.bucketId }, (a, b) => new
{
bucket = a.bucket,
items = b
}));
foreach (var g in groupedByBucket)
{
// We benefit here from that the collection types are passed by reference.
g.bucket.AddRange(b.items);
}
这也是假设CCD_ 1是给定的。如果这只是实现的一个工件,那么还有一种更简单的方法。这将生成列表。
当然,要小心,因为这些是不同的——这一个不会有任何空的存储桶,但第一个实现可以。我们还在创建新的bucket,而第一个实现没有;如果我们需要的话是好的,如果你已经在其他地方创建了它们,那就不好了。当然,第一个可以很容易地修改来创建它们。
var ListOfSuperBuckets = items
.GroupBy(c => new { c.bucketId, c.sBucketId })
.GroupBy(c => c.Key.sBucketId)
.Select(c => new SuperBucket
{
id = c.Key,
buckets = c.Select(b => new Bucket
{
id = b.Key.bucketId,
items = b.ToList()
}).ToList()
})
.ToList();
值得一提的是,所有这些ToList
调用都是为了保留我认为您拥有的合同。如果你不需要它们,你可以通过关闭它们来从LINQ的延迟执行中受益。这实际上是一个如何使用代码的问题,但这值得考虑。
您应该使用Dictionary
,这样您就可以按ID查找bucket和SuperBuckets,而不是搜索它们。
SuperBucket
应该有一个Dictionary<id_type,Bucket>
,可以用来按ID查找bucket,并且应该将SuperBuckets保留在Dictionary<id_type,SuperBucket>
中。(id_type
是您的ID类型——可能是字符串或int,但我无法从您的代码中分辨出来)
如果您不想修改现有的类,那么构建一个Dictionary<id_type, Dictionary<id_type, Bucket>>
并使用它。