質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

3回答

766閲覧

Javaにおける複数のEnumクラスをキーとするマップの効率的な実装

snorlax

総合スコア0

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

1グッド

1クリップ

投稿2023/04/28 23:03

編集2023/04/29 05:43

Javaにおける複数のEnumクラスをキーとするマップの効率的な実装

Javaで複数のEnumクラス,例えば,enum1,enum2があり,これらは同じ概念の名前を定義しています.そのため,以下のようにenum1, enum2の両方をキーとして使用するmapを利用する場面があります.

java

1public enum enum1 { 2 APPLE, 3 ORANGE 4} 5public enum enum2 { 6 APPLE, 7 BANANA 8} 9 10public static void main(String[] args) { 11 Map<Enum<?>, Object> map = new HashMap<>(); 12 map.put(enum1.APPLE, object1); 13 map.put(enum2.APPLE, object2); 14 ... 15}

状況としては,enum1はライブラリ側が定義,enum2はユーザ側が定義するものです.StringではなくEnum型を採用している理由は以下のとおりです.

  • ユーザが同じ名前を使用したとしても別々の定義として扱いたい.例えば,上記のAPPLEはそれぞれ別物として扱いたい.
  • 名前比較を大量に行うので,インスタンスによる比較で高速に処理したい.

さらに,上記のようなMapのインスタンスを大量に生成します.
Enumクラスを複数定義しているのでEnumMapは利用できませんが,実行時にはすべての定数が決まっているため,できるだけメモリ使用量,計算量ともに最小にしたいです(計算資源を多少気にする状況です).現在は,Enum<?>をキーとするHashMapを利用していますが,hashの衝突が発生しうる上に,負荷係数設定の関係でメモリも余分に使用しています.
より良い実装(Enum以外のクラスを使用する方法,効率的なマッピングの方法など)のアイデアがありましたら教えていただきたいです.

追記

効率に関しては,最終的には時間計算量の削減,次点で空間計算量の削減ですが,理論上改善しうる実装がないかという意図です.

Enumクラスは2つとは限りません.任意です.

考えたこと

実行時に enum1, enum2 の定数に動的にインデックス番号を割り振って,それによって配列操作をすればマッピング可能ですが,インデックス番号の割り振りに Map を使うので根本的解決にはならない.実行時に動的にインデックス番号を割り振って HashMap よりも高速にアクセスする方法はあるか?

neko_the_shadow👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2023/04/29 03:02

コード自体の問題でなく、またアイデアを募集という意味合いであれば、 Q&Aでは無く意見交換で書いたほうが適切と思います。 「高速」「効率」とはどう計測するのか、現在どの様な値で目標値はどれほどなのか等、感覚では無く客観的な値をご提示ください。
snorlax

2023/04/29 05:24

ご指摘ありがとうございます. 確かに意見交換的側面の強い質問ですが,teratail の質問ガイドには具体的な課題と解決策を求めている場合はQ&Aを推奨するとありましたので,そうさせていただきました. 効率に関しては,最終的には開発中のライブラリを使用した場合の時間計算量の削減,次点で空間計算量の削減ですが,さすがにすべて説明するわけにはいかないので,理論上改善しうる実装がないかという意図でした.例えば,文字列結合に + 演算子を使うより StringBuilder を使うと性能改善しうるというようなレベルでの話と捉えていただきたいと思っています.定量的な値を提示できていない点についてはお詫びいたします.
jimbe

2023/04/29 07:46

具体的というのは、このコードでこのデータを処理すると何秒掛かるが何秒で処理させるにはどうすれば良いかということであって、「理論上」という言葉がある時点で具体的では無いのではないでしょうか。 文字列の結合で + より StringBuilder をという話は、具体的なコードとその結果が存在しています。 https://www.google.com/search?q=java+%E6%96%87%E5%AD%97%E5%88%97%E7%B5%90%E5%90%88 これは理論上ではありません。
xebme

2023/04/29 08:32

概念上同じものならhashKey()とequals()が同じになる実装を考える。ただしMapに最後に格納したキーEnumが有効になるだろう。それでいいのかどうか。要件をより詳細に確認してください。
xebme

2023/04/29 08:47

hashCode()とequals()ですね。
guest

回答3

0

2次元配列

分類軸は2つで要素数が決まっているのでObject[][]とすればメモリ枠の上限になります。配列の要素に値の割り当てがなければnullです。

  • 配列の1次元添字はenum1,enum2,...から決定する
  • 配列の2次元添字はordinal()から決定する
    oridinal()が等しければ概念的に同じ。2次元配列のサイズは揃っている
    余裕があればEnumMapを使えるかを検討

配列の1次元添字決定はHashMapを使うしかなさそう。あるいは、HashMapと同様な添字決定を自作するか、量が少なければ線形探索も考えられます。工夫の余地がありそうです。

分割された集合

もしも、enum1,enum2,... ごとに集合が分割されているなら、それぞれの集合で1次元配列の処理に注力すればよく、構造が簡単になります。また、データ量が多ければ分割された集合ごとに並列化することができます。

投稿2023/04/29 22:36

編集2023/04/30 04:43
xebme

総合スコア1081

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

アイデア/ヒント留まりですが...

Java

1enum Fruit { 2 APPLE, 3 BANANA, 4 CHERRY 5} 6 7public class foo { 8 public static void main(String[] args) { 9 for ( var f : Fruit.values() ) { 10 System.out.println(f.ordinal() +" : "+ f.toString()); 11 } 12 } 13}

これでFruit内の各値に対応する順序番号(ordinal())が得られます。
なのでたとえば enum e1 に対しては 10+順序番号、enum e2 に対しては 20+順序番号 はユニークな値となります。(各enumの列挙数が10を超えなければ)
この値をハッシュのkey(あるいは配列のindex)とするのはいかがでしょう?

投稿2023/04/29 11:44

episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

xebme

2023/04/29 12:08

enumだからequals()は自分のインスタンスだけと一致する。同じ概念のenumはhashCode()を共有する ...
xebme

2023/05/01 08:33

シノニム用の空きスロットを用意していると考えられます。事前にサイズを決められるので拡張不要。同じ概念を集めるには良いアイデアですね。
guest

0

列挙子に1:1で対応する値が欲しいという要件であれば、Mapを使わず、Enumのフィールドとして定義する方法があります。

java:Enum1.java

1public enum Enum1 { 2 APPLE("Apple"), 3 ORANGE("Orange"); 4 5 private Enum1(String name) { 6 this.name = name; 7 } 8 private String name; 9 public String getName() { 10 return name; 11 } 12}

上記のやりかたがそもそも要件とマッチするのか、マッチしたとしてパフォーマンス上の問題を解決するのかについては、書いていただいた内容からではこちらから判断しかねるものです。修正前と修正後でどれだけ改善したのか、定量的に計測されることをお勧めします。

投稿2023/04/29 02:53

neko_the_shadow

総合スコア2230

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

snorlax

2023/04/29 05:28

それぞれの定数に,実行後に動的に値が対応します. また,Mapは複数作成され,それぞれ別の値が対応するため,Enumクラスのメソッドとして実装するのは難しいと考えています. 要件がわかりにくくて申し訳ありません.
snorlax

2023/04/29 05:30

現段階では明確にパフォーマンス改善する実装を求めているわけではなく,改善しうる可能性のある実装アイデアを求めていました.ご意見ありがとうございます.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問