6

私は本質的に名前と値のペアのギザギザの配列を持っています - これから一意の名前の値のセットを生成する必要があります。ジャグ配列は約 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;
4

6 に答える 6

12

9分以上から0.34秒で実行しています

問題は、KeyValuePair 構造体を比較するときです。これを回避するには、比較オブジェクトを作成し、そのインスタンスを Dictionary に渡します。

私が判断できることから、 KeyValuePair.GetHashCode() はそのKeyオブジェクトのハッシュコードを返します (この例では、最もユニークでないオブジェクト)。

ディクショナリは各項目を追加 (およびその存在をチェック) するときに、Equals 関数と GetHashCode 関数の両方を使用しますが、ハッシュコードがあまり一意でない場合は Equals 関数に依存する必要があります。

よりユニークな GetHashCode 関数を提供することで、Equals 関数を実行する頻度がはるかに少なくなります。また、Equals 関数を最適化して、よりユニークなキーの前に、よりユニークな値を比較しました。

86,000 * 10,000 の一意のプロパティを持つ 11 のアイテムは、以下の比較オブジェクトを使用して 0.34 秒で実行されます (比較オブジェクトを使用しない場合、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();
        }
    }

編集: 1 つの文字列 (文字列 = 名前 + 値の KeyValuePair ではなく) の場合、約 2 倍の速度になります。これはとても興味深い問題で、私はこれにかなりの時間を費やしました(ただし、少し静かになりました)。

于 2008-10-30T20:21:29.797 に答える
0

コードをプロファイリングしましたか? foreach ループがボトルネックであり、retriever.GetVehicles() ではないことは確かですか?

私は小さなテスト プロジェクトを作成し、レトリバーを偽装して 86.000 X 11 の値を返させました。私の最初の試行は 5 秒で実行され、含まれているデータが作成されました。

最初のキーが「0#0」で最後の「85999#10」であるキーと値の両方に同じ値を使用しました。

その後、ガイドに切り替えました。同じ結果です。

次に、次のようにキーを長くしました。

        var s = Guid.NewGuid().ToString();
        return s + s + s + s + s + s + s+ s + s + s;

今では約10秒かかりました。

次に、キーを非常に長くすると、メモリ不足の例外が発生しました。コンピューターにスワップ ファイルがないため、すぐにこの例外が発生しました。

あなたの鍵はどのくらいですか?仮想メモリの消費がパフォーマンスの低下の原因ですか?

于 2008-10-25T21:26:53.940 に答える
0

Dictionary拡張しない理由を使用する代わりにKeyedCollection<TKey, TItem>? ドキュメントによると:

キーが値に埋め込まれているコレクションの抽象基本クラスを提供します。

次に、関数をオーバーライドする必要がありますprotected TKey GetKeyForItem(TItem item)。と のハイブリッドなので、かなり高速になる可能性が高いIList<T>IDictionary<TKey, TValue>思います。

于 2008-10-24T11:11:43.330 に答える
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));

トリックを行うでしょう。

于 2008-10-24T11:22:20.237 に答える
0

各キーと値のペアと生成している一意の値との間に特定の相関関係が必要ない場合は、GUID を使用できますか? 問題は、現在の「キー」がこのギザギザの配列で一意ではないことだと思います。

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 と元々持っていたものとの間に意味的な関係がないため、これからデータを取得する方法がわかりません...

質問でさらに情報を提供できますか?

于 2008-10-24T10:25:44.080 に答える
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;
}
于 2008-10-24T10:35:29.787 に答える