将两种不同的信息组合成二进制代码
combining two different information in binary code
我有Dictionary<string,T>
,其中字符串代表记录的键,我还有另外两条关于记录的信息,我需要为字典中的每条记录维护,它们是记录的类别及其冗余度(重复了多少次)。
例如:记录XYZ1属于类别1,重复了1次。因此实现必须是这样的:
"XYZ1", {1,1}
现在继续,我可能会在我的数据集中遇到相同的记录,因此必须像这样更新键的值:
"XYZ1", {1,2}
"XYZ1", {1,3}
...
由于我正在处理大量记录,例如 100K,我尝试了这种方法,但它似乎效率低下,因为从字典中获取值然后切片 {1,1}
然后将两个切片转换为整数的额外工作量给执行带来很多开销。
我正在考虑使用二进制数字来表示类别和重排,并可能使用位掩码来获取这些片段。
编辑: 我尝试使用具有 2 个属性的对象 ,然后使用 Tuple<int,int>
。复杂性变得更糟了!
我的问题:是否可以这样做?
如果没有(在复杂性方面)有什么建议吗?
类别似乎永远不会改变。因此,与其使用简单的字符串作为字典的键,不如这样做:
Dictionary<Tuple<string,int>,int>
其中字典的键是 Tuple<string,int>
,其中 string
是记录,int
是类别。那么字典中的值只是一个计数。
字典可能是您要完成的任务最快的数据结构,因为它具有接近恒定的时间 O(1) 查找和输入。
您可以通过使用元组来加快速度,因为现在类别是键的一部分,不再是您必须单独访问的一些信息。
同时,您也可以将字符串作为键并存储一个Tuple<int,int>
作为值,只需将Item1
设置为类别,将Item2
设置为计数。
两种方式的速度大致相当。无论哪种方式,以这种方式处理 100k 条记录应该都非常快。
你是什么类型的T
?您可以定义一个自定义类型,其中包含您需要的信息(类别和出现次数)。
class MyInfo {
public int c { get; set; }
public int o { get; set; }
}
Dictionary<String, MyInfo> data;
然后在遍历您的数据时,您可以轻松地检查某个键是否已经存在。如果是,则增加出现次数,否则插入一个新元素。
MyInfo d;
foreach (var e in elements) {
if (!data.TryGet(e.key, out d))
data.Add(e.key, new MyInfo { c = e.cat, o= 1});
else
d.o++;
}
编辑
您也可以将类别和出现次数合并为一个 UInt64。例如取高32位的类别(即可以有40亿个类别)和低32位的出现次数(即每个键可以出现40亿次)
Dictionary<string, UInt64> data;
UInt64 d;
foreach (var e in elements) {
if (!data.TryGet(e.key, out d))
data[e.key] = (e.cat << 32) + 1;
else
data[e.key] = d + 1;
}
如果您想获取某个特定键的出现次数,您只需检查值的相应部分即可。
var d = data["somekey"];
var occurrences = d & 0xFFFFFFFF;
var category = d >> 32;
我有Dictionary<string,T>
,其中字符串代表记录的键,我还有另外两条关于记录的信息,我需要为字典中的每条记录维护,它们是记录的类别及其冗余度(重复了多少次)。
例如:记录XYZ1属于类别1,重复了1次。因此实现必须是这样的:
"XYZ1", {1,1}
现在继续,我可能会在我的数据集中遇到相同的记录,因此必须像这样更新键的值:
"XYZ1", {1,2}
"XYZ1", {1,3}
...
由于我正在处理大量记录,例如 100K,我尝试了这种方法,但它似乎效率低下,因为从字典中获取值然后切片 {1,1}
然后将两个切片转换为整数的额外工作量给执行带来很多开销。
我正在考虑使用二进制数字来表示类别和重排,并可能使用位掩码来获取这些片段。
编辑: 我尝试使用具有 2 个属性的对象 ,然后使用 Tuple<int,int>
。复杂性变得更糟了!
我的问题:是否可以这样做?
如果没有(在复杂性方面)有什么建议吗?
类别似乎永远不会改变。因此,与其使用简单的字符串作为字典的键,不如这样做:
Dictionary<Tuple<string,int>,int>
其中字典的键是 Tuple<string,int>
,其中 string
是记录,int
是类别。那么字典中的值只是一个计数。
字典可能是您要完成的任务最快的数据结构,因为它具有接近恒定的时间 O(1) 查找和输入。
您可以通过使用元组来加快速度,因为现在类别是键的一部分,不再是您必须单独访问的一些信息。
同时,您也可以将字符串作为键并存储一个Tuple<int,int>
作为值,只需将Item1
设置为类别,将Item2
设置为计数。
两种方式的速度大致相当。无论哪种方式,以这种方式处理 100k 条记录应该都非常快。
你是什么类型的T
?您可以定义一个自定义类型,其中包含您需要的信息(类别和出现次数)。
class MyInfo {
public int c { get; set; }
public int o { get; set; }
}
Dictionary<String, MyInfo> data;
然后在遍历您的数据时,您可以轻松地检查某个键是否已经存在。如果是,则增加出现次数,否则插入一个新元素。
MyInfo d;
foreach (var e in elements) {
if (!data.TryGet(e.key, out d))
data.Add(e.key, new MyInfo { c = e.cat, o= 1});
else
d.o++;
}
编辑
您也可以将类别和出现次数合并为一个 UInt64。例如取高32位的类别(即可以有40亿个类别)和低32位的出现次数(即每个键可以出现40亿次)
Dictionary<string, UInt64> data;
UInt64 d;
foreach (var e in elements) {
if (!data.TryGet(e.key, out d))
data[e.key] = (e.cat << 32) + 1;
else
data[e.key] = d + 1;
}
如果您想获取某个特定键的出现次数,您只需检查值的相应部分即可。
var d = data["somekey"];
var occurrences = d & 0xFFFFFFFF;
var category = d >> 32;