1

単純な Java オブジェクトがあるとしましょう。それを DefinedData と呼びましょう。これには、文字列、整数、列挙型、さらには 1 つまたは 2 つの文字列のセットなど、さまざまなタイプの最終フィールドが多数含まれます。全体として、これは比較的単純なデータ コンテナーにすぎません。これらは潜在的に 1k から 2k あり、すべて静的な最終オブジェクトです。これらのフィールドのほとんどは、他の DefinedData オブジェクトがそのフィールドに対して同じ値を持つことがないという点で一意です。

これらは (DefinedData, Object) の Map に配置されます。ここで、DefinedData オブジェクトがあれば、そのオブジェクトを Map から簡単に取得できますが、一意のフィールド値が 1 つしかない場合はどうでしょうか? それを単にマップに渡すことはできません。キーとチェックを反復処理する必要があります。これは、DefinedData の各フィールドのルックアップ メソッドでマップをラップすることを意味します。実行可能ですが、特にマップに多くの値があり、多くのルックアップがある場合、これは可能です。それか、DefinedData オブジェクトのルックアップが必要になります。これも一連のマップになります...

これは、データベースの仕事 (任意の列に基づいて検索する) のように思えますが、これはこの特定の問題に対する適切な解決策ではありません。また、それぞれが DefinedData から Object に 1 つのフィールドをマッピングするさまざまなマップを持つことは避けたいと思います。私が見たマルチキー マップは、1 つだけでなくすべてのキー値を必要とするため、適用できません。この特定の問題を処理できるマップ、コレクション、またはその他の実装はありますか?

4

2 に答える 2

0

Indexerこれを提案するのは躊躇しますが、提供されたオブジェクトのフィールドを使用して、リフレクションを介して単一のマップを自動生成するある種のクラスの背後にルックアップをカプセル化することができます。

単一のマップとは、フィールド名とデータの両方に基づいてキーを作成するインデクサー全体の単一のマップを意味します (たとえば、フィールド名を表す文字列をデータの文字列表現と連結します)。

インデクサーに対するルックアップは、フィールド名とデータ値の両方を提供し、インデクサーによってカプセル化された単一のマップでルックアップされます。

これは、インデクサーが代わりにマップのマップ(フィールド名のマップからデータのマップへのマップ) に支えられている同様のソリューションよりも必ずしも利点があるとは思いません。

インデクサーは注釈を使用するように設計することもできます。これにより、すべてのフィールドが索引付けされるわけではなく、適切に注釈が付けられたフィールドのみが索引付けされます (またはその逆で、注釈を使用してフィールドを除外します)。

全体として、マップ ソリューションのマップは、複雑なキー アセンブリのステップ (特定のフィールド データ タイプでは複雑になる可能性があります) を省略できるため、簡単だと思います。どちらの場合でも、マップを自動生成する にすべてをカプセル化するのIndexerが最善の方法のようです。

アップデート:

型クラスの一般化されていない概念の簡単な証明を行いましたIndexer(map of maps アプローチを使用)。 これは決して完成した作品ではありませんが、上記の概念を示しています。主要な欠点の 1 つは Bean への依存であるため、アクセサー メソッドのないパブリック フィールドとプライベート フィールドの両方がこのインデクサーから見えません。

public class Indexer
{
    private Map<String,Map<Object,Set<Object>>> index = new HashMap<String,Map<Object,Set<Object>>>();

    // Add an object to the index, all properties are indexed.
    public void add(Object object) throws Exception
    {
        BeanInfo info = Introspector.getBeanInfo(object.getClass());

        PropertyDescriptor[] propertyDescriptors = info.getPropertyDescriptors();
        for (PropertyDescriptor descriptor : propertyDescriptors)
        {
            String fieldName = descriptor.getName();
            Map<Object,Set<Object>> map = index.get(fieldName);
            if (map == null)
            {
                map = new HashMap<Object,Set<Object>>();
                index.put(fieldName, map);
            }
            Method method = descriptor.getReadMethod();
            Object data = method.invoke(object);
            Set<Object> set = map.get(data);
            if (set == null)
            {
                set = new HashSet<Object>();
                map.put(data, set);
            }
            set.add(object);
        }

    }

    // Retrieve the set of all objects from the index whose property matches the supplied.
    public Set<Object> get(String fieldName, Object value)
    {
        Map<Object,Set<Object>> map = index.get(fieldName);
        if (map != null)
        {
            Set<Object> set = map.get(value);
            if (set != null)
            {
                return Collections.unmodifiableSet(set);
            }
        }

        return null;
    }
}
于 2013-11-18T23:52:38.407 に答える
0

複数のマップを持つことを回避する唯一の方法は、何らかの方法ですべての DefinedData オブジェクトを反復処理することです。理由は、リクエストが行われるまで、それらを分割またはソートする方法を知る方法がないためです。

リンゴの入ったバケツを持っている場合を例に挙げることができます。いつでも誰かがやって来て、特定の色、特定の種類、または特定のサイズを要求することがあります. これらのカテゴリの 1 つを選択して並べ替える必要があり、他のカテゴリはすべてのリンゴから検索する必要があります。同じリンゴのセットが 3 つあればいいのに。各カテゴリに 1 つ。

複数のマップを使用すると、より高速なソリューションになりますが、より多くのメモリが必要になりますが、反復は実現が容易になり、速度が低下し、メモリの使用量が少なくなります。

于 2013-11-18T23:06:35.830 に答える