我本质上是一个参差不齐的名称值对数组 - 我需要从中生成一组唯一的名称值。锯齿状阵列约为86,000 x 11值。
对我来说,以何种方式存储名称值对(单个字符串“name = value”或专门的类,例如KeyValuePair)并不重要。
其他信息:有40个不同的名称和更多的不同值 - 可能在10,000个值的区域内。
我正在使用C#和.NET 2.0(并且性能非常差)我认为将整个锯齿状阵列推送到sql数据库并从那里做一个不同的选择可能会更好。
以下是我使用的当前代码:
List<List<KeyValuePair<string,string>>> vehicleList = retriever.GetVehicles();
this.statsLabel.Text = "Unique Vehicles: " + vehicleList.Count;
Dictionary<KeyValuePair<string, string>, int> uniqueProperties = new Dictionary<KeyValuePair<string, string>, int>();
foreach (List<KeyValuePair<string, string>> vehicle in vehicleList)
{
foreach (KeyValuePair<string, string> property in vehicle)
{
if (!uniqueProperties.ContainsKey(property))
{
uniqueProperties.Add(property, 0);
}
}
}
this.statsLabel.Text += "\rUnique Properties: " + uniqueProperties.Count;
答案 0 :(得分:12)
我让它在0.34秒内从9分钟以上运行
问题在于比较KeyValuePair结构。 我通过编写一个比较器对象并将其实例传递给Dictionary来解决这个问题。
根据我的判断,KeyValuePair.GetHashCode()返回它的Key
对象的哈希码(在这个例子中是最不唯一的对象)。
当字典添加(并检查存在)每个项时,它使用Equals和GetHashCode函数,但是当hashcode不那么独特时必须依赖Equals函数。
通过提供更独特的GetHashCode函数,它远远少于Equals函数。我还优化了Equals函数,以便在较少的unqiue键之前比较更独特的值。
使用下面的比较器对象,在0.34秒内运行86,000 * 11个具有10,000个唯一属性的项目(没有比较器对象需要9分22秒)
希望这会有所帮助:)
class StringPairComparer
: IEqualityComparer<KeyValuePair<string, string>>
{
public bool Equals(KeyValuePair<string, string> x, KeyValuePair<string, string> y)
{
return x.Value == y.Value && x.Key == y.Key;
}
public int GetHashCode(KeyValuePair<string, string> obj)
{
return (obj.Key + obj.Value).GetHashCode();
}
}
编辑:如果它只是一个字符串(而不是KeyValuePair,其中string = Name + Value),它的速度大约是其两倍。这是一个很好的有趣的问题,我已经花费了很多时间 faaaaaar (虽然我学会了一点安静)
答案 1 :(得分:0)
如果您不需要在每个键/值对与您生成的唯一值之间存在任何特定关联,那么您可以使用GUID吗?我假设问题是你当前的'Key'在这个锯齿状数组中不是唯一的。
Dictionary<System.Guid, KeyValuePair<string, string>> myDict
= new Dictionary<Guid, KeyValuePair<string, string>>();
foreach of your key values in their current format
myDict.Add(System.Guid.NewGuid(), new KeyValuePair<string, string>(yourKey, yourvalue))
听起来它会存储你需要的内容,但我不知道你将如何从中提取数据,因为生成Guid&amp;之间没有语义关系。你原来有什么......
您可以在问题中提供更多信息吗?
答案 2 :(得分:0)
使用KeyValuePair作为包装类,然后创建一个字典,或者创建一个集合?或者实现自己的包装器来覆盖Equals和GetHashCode。
Dictionary<KeyValuePair, bool> mySet;
for(int i = 0; i < keys.length; ++i)
{
KeyValuePair kvp = new KeyValuePair(keys[i], values[i]);
mySet[kvp] = true;
}
答案 3 :(得分:0)
而不是使用Dictionary
为什么不延长KeyedCollection<TKey, TItem>
?根据文件:
为其键嵌入值的集合提供抽象基类。
然后您需要覆盖protected TKey GetKeyForItem(TItem item)
功能。因为它是IList<T>
和IDictionary<TKey, TValue>
之间的混合体,我认为它可能会非常快。
答案 4 :(得分:0)
怎么样:
Dictionary<NameValuePair,int> hs = new Dictionary<NameValuePair,int>();
foreach (i in jaggedArray)
{
foreach (j in i)
{
if (!hs.ContainsKey(j))
{
hs.Add(j, 0);
}
}
}
IEnumerable<NameValuePair> unique = hs.Keys;
当然,如果您使用的是C#3.0,.NET 3.5:
var hs = new HashSet<NameValuePair>();
hs.UnionWith(jaggedArray.SelectMany(item => item));
会做到这一点。
答案 5 :(得分:0)
您是否描述过您的代码?您确定foreach循环是瓶颈,而不是retrievever.GetVehicles()?
我确实创建了一个小型测试项目,我伪造了检索器并让它返回86.000 X 11值。我的第一次尝试在5秒内完成,创建了包含的数据。
我对第一个键为“0#0”和最后一个“85999#10”的键和值使用了相同的值。
然后我切换到guids。结果相同。
然后我把钥匙做得更长了,就像这样:
var s = Guid.NewGuid().ToString();
return s + s + s + s + s + s + s+ s + s + s;
现在花了差不多10秒钟。
然后我疯狂地做了很长的键并且出现了内存异常。我的计算机上没有交换文件,所以我立即得到了这个例外。
你的钥匙多长时间了?你的虚拟内存消耗是你性能不佳的原因吗?