8

次のようなことをしているコードに出くわしました:

Map<String,String> fullNameById = buildMap1(dataSource1);
Map<String,String> nameById = buildMap2(dataSource2);
Map<String,String> nameByFullName = new HashMap<String,String>();
Map<String,String> idByName = new HashMap<String,String>();

Set<String> ids = fullNameById.keySet();
for (String nextId : ids) {
  String name = nameById.get(nextId);
  String fullName = fullNameById.get(nextId);
  nameByFullName.put(fullName, name);
  idByName.put(name, nextId);
}

何が起こっているのかを理解するために、私はそれを数分間じっと見つめなければなりませんでした。そのすべてが、id の結合操作と、元のマップの 1 つの反転に相当します。Id、FullName、および Name は常に 1:1:1 であるため、これを単純化する方法が必要であると思われました。また、最初の 2 つのマップが二度と使用されないことも発見しました。また、上記のコードは少し読みにくいことがわかりました。だから私はそれを(私にとって)よりきれいに読めるこのようなものに置き換えることを検討しています

Table<String, String, String> relations = HashBasedTable.create();

addRelationships1(dataSource1, relations);
addRelationships2(dataSource2, relations);

Map<String,String> idByName = relations.column("hasId");
Map<String,String> nameByFullName = relations.column("hasName");
relations = null; // not used hereafter

addRelationships1 で私は

relations.put(id, "hasFullName", fullname);

そして、クエリが値を生成するaddRelationships2で、idnameはそうします

relations.put(relations.remove(id,"hasFullName"), "hasName", name);
relations.put(name, "hasId", id);

だから私の質問はこれらです:

  1. プロセッサやメモリ、または GC の負荷を介して行った作業に、非効率性が潜んでいますか? そうは思いませんが、Table の効率性についてはあまり詳しくありません。Table オブジェクトが の後に GC されないことは承知してrelations = nullいます。次のかなり長いコード セクションで、Table オブジェクトが再び使用されないことを伝えたいだけです。
  2. 効率が上がりましたか?私は自分が持っていることと持っていないことを自分自身に納得させたり、納得させたりし続けています。
  3. これは読みやすいと思いますか?それとも私が書いたから読みやすいだけですか?Tableあまり知られていないので、ちょっと心配です。一方、最上位レベルでは、「2 つのソースからデータを収集し、そこからこれら 2 つのマップを作成する」ことが明確に示されています。また、他の 2 つのマップが使用されている (または使用されていない) かどうか、またはどこで使用されているかを疑問に思わないという事実も気に入っています。
  4. 上記のいずれよりも、よりクリーンで、より速く、より簡単な方法はありますか?

ここで最適化の初期/後期の議論を行わないようにしてください。私はその落とし穴をよく知っています。パフォーマンスを損なうことなく可読性が向上する場合、私は満足しています。パフォーマンスの向上は素晴らしいボーナスです。

注:ここでは変数とメソッドの名前をサニタイズして、ビジネス エリアが議論の邪魔にならないようにしています。同様に、最終的なコードはもちろん生の文字列ではなく定数を使用します。

4

2 に答える 2

17

そこで、自分でミニベンチマークを行い、実行時間の点で2つの方法にほとんど違いがないという結論に達しました。実行をデータセットサイズと交換することにより、処理されるデータの合計サイズを一定に保ちました。私は4回の実行を行い、4回の実行すべての中から各実装の最短時間を選択しました。安心して、両方の実装は同じ実行で常に最速でした。私のコードはここにあります。これが私の結果です:

Case                      Maps (ms)   Table (ms)    Table vs Maps
100000 runs of size 10    2931        3035          104%
10000 runs of size 100    2989        3033          101%
1000 runs of size 1000    3129        3160          101%
100 runs of size 10000    4126        4429          107%
10 runs of size 100000    5081        5866          115%
1 run  of size 1000000    5489        5160          94%

したがって、テーブルの使用は、小さなデータセットでは少し遅くなるようです。何か面白いことが10万前後で起こり、100万までにテーブルは実際に速くなります。私のデータは100から1000の範囲でハングアウトするので、少なくとも実行時にはパフォーマンスはほぼ同じになるはずです。

読みやすさに関しては、誰かが近くで何が起こっているのかを理解しようとしてコードを読もうとすると、意図が非常にわかりやすくなると思います。彼らが実際にこのコードのビットをデバッグしなければならない場合、それはあまり一般的ではないので少し難しいかもしれませんTable、そして理解するためにいくらかの洗練が必要です。

私が確信していないもう1つのことは、ハッシュマップを作成する方が効率的かどうか、またはマップのすべてのキーが後で繰り返される場合にテーブルを直接クエリする方が効率的かどうかです。しかし、それは別の質問です:)

そして、コメディーの結末は、実際にコードをさらに分析すると(数百行)、ロギング以外でのnameByFullname.get()の唯一の重要な使用法(疑わしい値)は、結果をidByNameに渡すことであることがわかりました。 。得る()。したがって、最終的には、実際にはidByFullNameマップとidByNameマップを作成し、代わりに結合する必要はなく、とにかくテーブル全体を削除します。しかし、それは私が推測する興味深いSOの質問になりました。

于 2013-03-07T19:15:57.487 に答える
5

tl; drですが、元のデザインからさらに大きな一歩を踏み出す必要があるのではないかと思います。DBテーブルをシミュレートすることは良い練習になるかもしれませんが、私にとってはあなたのコードは本当に読みやすいものではありません。

  1. 私がやったことに潜んでいる非効率性はありますか...わかりません。
  2. 効率は上がりましたか?最初に測定する必要があります。一部の間接参照を削除することは確かに役立ちますが、より複雑なデータ構造を使用すると、それが相殺される可能性があります。そして、一般的なパフォーマンスは単純に複雑すぎます。
  3. これはもっと読みやすいと思いますか?そうではないと思います。
  4. 上記のいずれよりも、より優れた、よりクリーンで、より速く、より簡単な方法がありますか?そうだといい....

そのようなコードで迷子になるのは、すべてに文字列を使用することです。引数として間違った文字列を渡すのは簡単すぎます。したがって、それらをオブジェクトに集約し、それらの任意の部分を介してオブジェクトにアクセスするためのマップを提供することをお勧めします。これが行うべきと同じくらい些細なこと:

class IdNameAndFullName {
    String id, name, fullName;
}

class IdNameAndFullNameMaps {
    Map<String, IdNameAndFullName> byId;
    Map<String, IdNameAndFullName> byName;
    Map<String, IdNameAndFullName> byFullName;
}

IdNameAndFullNameMaps明らかに、クラスを。に置き換えることができTableます。ただし、既存の優れたデータ構造を使用する以外に、利点はありません。欠点は次のとおりです。

  • 効率の低下
  • 読みやすさの喪失(Tableまったく同じ理由でここでは使用しませTuple
  • 文字列キー(「hasId」および「hasName」)の使用。
于 2013-03-02T00:29:33.087 に答える