【问题标题】:Choosing the data structure for orgaininsng data with list of values in java在java中选择具有值列表的数据结构
【发布时间】:2015-06-14 00:59:19
【问题描述】:

我有一个如下所示的地图,其中有一个键和值的类型为List

Map<String, List<String> newdatamap = new HashMap<>();
map.put ("RtyName", Arrays.asList("wpn", "wpfnb", "dgeft", "xbthy"));
map.put ("rtyRate", Arrays.asList("dd", "ww", "trrty", "httyure"))

我想在前一个地图上添加另一个地图,这样就有一个键,它的值就是上面的地图。这是正确的数据结构吗?我们如何实现它?

我想要如下所示的东西

Key         Value

B1          RtyName  ----> "weepn", "weepfnb", "eedgeft", "xbteehy"
            rtyRate ----->"deed", "ww", "terrty", "hteetyure"



B2          RtyName  ----> "SSSweepn", "wpefSSSnb", "GGeGdgeft", "xbteYYYYhy"
            rtyRate ----->"WWded", "wTeTYw", "YYYYtrerty", "IIIehttyure"

如上图,只给map引入了一个新的key,它的value就是之前的map。

所以它就像Map&lt;String, Map&lt;String, List&lt;String&gt;&gt;&gt; whis 变成了一个复杂的数据结构,我可以将数据结构组织为 例如一个包含地图的类,所以它会像

Map<B1 , RtyName>
Map<B2 ,rtyRate>

和 payer nae 包含值列表,例如

 RtyName  ----> "SSSweepn", "wpefSSSnb", "GGeGdgeft", "xbteYYYYhy"
  rtyRate ----->"deed", "ww", "terrty", "hteetyure"

因此,在上述结构中,复杂性会很低,因为在 B1 的最后,我必须搜索将是 RtyName 的密钥,并针对付款人名称进一步搜索值,这些值将是“wpn”、“wpfnb”、“dgeft” ", "xbthy"

请告知地图是否最好,或者是否有其他更好的数据结构也可以获得这个。

我想到的一个数据结构是 Guava's Table

  final Table<String, String, List<String>> values = HashBasedTable.create();
values.put("B1", "RtyName", Lists.newArrayList("weepn", "weepfnb", "eedgeft", "xbteehy"));
System.out.println(values.get("B1", "RtyName")); // prints the list

我的目标是我可以拥有的任何数据结构,对于 B1,我将获得 Rtyname,对于 Rtyname,我将获得可能的值列表

【问题讨论】:

  • 为什么不声明一个简单的 POJO,其中包含 RtynamertyRate 的两个列表,并将该类的对象放入映射而不是嵌套映射和列表?
  • 看起来很合理。除了复杂性,还有哪些问题?您是否需要在不知道 B1 或 B2 密钥的情况下访问成员?当您拥有一组有限的已知值时,请考虑使用 enum 而不是 String
  • 为了选择数据结构,首先要写下要求,尤其是插入、删除和搜索的形式。
  • 您的最后一个示例表明您只需要可以使用两个标识符/键组合来引用的列表。如果是这种情况(是这种情况吗?),最好有一个函数,以哈希函数的方式,根据这两个值(并且与顺序无关)生成一个键,然后简单地使用此函数引用单个 Map&lt;String, List&lt;String&gt; 数据结构。
  • @ROman vottner 能否请您展示一下,假设创建了一个名为 ABC 的 pojo,并创建了 Rtyname 和 rtyRAte 的两个列表,那么我将如何管理

标签: java data-structures


【解决方案1】:

我会这样做:

Map<Integer, List<String>> dataMap = new HashMap<>();
dataMap.put("B1".hashCode()+"RtyName".hashCode(), Arrays.asList("weepn", "weepfnb", "eedgeft", "xbteehy"));
dataMap.put("B1".hashCode()+"rtyRate".hashCode(), Arrays.asList("deed", "ww", "terrty", "hteetyure"));
dataMap.put("B2".hashCode()+"RtyName".hashCode(), Arrays.asList("SSSweepn", "wpefSSSnb", "GGeGdgeft", "xbteYYYYhy"));
dataMap.put("B2".hashCode()+"rtyRate".hashCode(), Arrays.asList("WWded", "wTeTYw", "YYYYtrerty", "IIIehttyure"));

代表:

B1, RtyName  ----> "weepn", "weepfnb", "eedgeft", "xbteehy"
B1, rtyRate ----->"deed", "ww", "terrty", "hteetyure"

B2, RtyName  ----> "SSSweepn", "wpefSSSnb", "GGeGdgeft", "xbteYYYYhy"
B2, rtyRate ----->"WWded", "wTeTYw", "YYYYtrerty", "IIIehttyure"

请注意,hashCode 只是满足我需要的 String 类中的一个方便的函数。如果您愿意,您可以自己滚动返回 String 密钥(或其他任何内容)。

实际上,由于您的原始方法不需要与顺序无关的函数,您甚至可以连接 String 键以用作新键:

dataMap.put("B1"+"RtyName", Arrays.asList(/*your list here*/));

这比第一种方法更不方便(并且在编程上不如“好”),但仍然比嵌套Map 类好得多。 (并且在输出时使按键比hashCode 更容易识别。)

双向映射

值作为键

如果您希望每个 List 值映射到键以及反之亦然,则需要第二个 Map

Map<List<String>, String> valueMap = new HashMap<>(); //New map for value->key 
for(String key: dataMap.keySet()) //Get all keys
    valueMap.put(dataMap.get(key), key); //Create mapping value->key

Value 中的每一项作为 Key

如果您希望values 列表中的每个String 项目映射到keys 以及反之亦然,您需要第二个Map

Map<String, String> itemMap = new HashMap<>(); //New map for item->key mapping
    for(String key: dataMap.keySet()) //Get all keys and iterate through
        for(String item: dataMap.get(key)) //For each item in your value list
            itemMap.put(item, key); //Create new mapping item->key

【讨论】:

【解决方案2】:

如你所愿:

您只需定义一个类,在本例中为 ABC,因为您建议使用该名称,其中包含两个列表,RtyNamertyRate 列表:

public class ABC {
    private List<String> RtyName;
    private List<String> rtyRate;

    public ABC(List<String> RtyName, List<String> rtyRate) {
        setRtyNames(RtyName);
        setRtyRates(rtyRate);
    }

    public void setRtyNames(List<String> RtyName) {
        this.RtyName = RtyName;
    }

    public List<String> getRtyNames() {
        return this.RtyName;
    }

    public void setRtyRates(List<String> rtyRate) {
        this.rtyRate = rtyRate;
    }

    public List<String> getRtyRates() {
        return this.rtyRate;
    }
}

一旦此类准备就绪,您可以将地图定义更改为:

Map<String, ABC> newdatamap = new HashMap<>();

并为它分配新值,就像您之前所做的那样 - 不是将这些列表嵌套在另一个映射中并将此映射放入外部映射中,而是创建一个新的 ABC 实例,提供两个列表作为输入参数并将生成的 ABC 对象放入地图(正式为外部地图):

List<String> RtyName = Arrays.asList("wpn", "wpfnb", "dgeft", "xbthy");
List<String> rtyRate = Arrays.asList("dd", "ww", "trrty", "httyure");
newdatamap.put("B1", new ABC(RtyName, rtyRate));

您也可以将这些列表直接分配为输入参数:

newdatamap.put("B2", new ABC(Arrays.asList("SSSweepn", "wpefSSSnb", "GGeGdgeft", "xbteYYYYhy"), 
                             Arrays.asList("WWded", "wTeTYw", "YYYYtrerty", "IIIehttyure"));

现在只需调用 get(String) 即可检索条目,就像您以前所做的那样:

ABC data = newdatamap.get("B1);

您也可以直接检索其中一个列表,例如:

List<String> RtyNames = newdatamap.get("B1").getRtyNames();

在我看来,这更容易同时管理和阅读。最重要的是,您还可以获得运行时安全性,因为您不会遇到 RtyNamertyRate 的最终输入错误。

重新设计更新

如果 RtyName 条目和 rtyRate 条目总是齐头并进,f.e. wpn 是名称,dd 是分配的费率,将这些字段组合在一起是有意义的。因此,您可以重构代码以进一步减少一个列表并引入一个新类:

public class RtyEntry {
    private String name;
    private String rate;

    public RtyEntry(String name, String rate) {
        setName(name);
        setRate(rate);
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public void setRate(String rate) {
        this.rate = rate;
    }

    public String getRate() {
        return this.rate;
    }
}

如果您现在将 ABC 更改为仅包含一个 RtyEntry 对象列表,如下所示:

public class ABC {
    private List<RtyEntry> rtyEntries;

    public ABC(List<RtyEntry> rtyEntries) {
        this.rtyEntries = rtyEntries;
    }

    public ABC() {
        this.rtyEntries = new ArrayList<>();
    }

    public void setRtyEntries(List<RtyEntry> rtyEntries) {
        this.rtyEntries = rtyEntries;
    }

    public List<RtyEntry> getRtyEntries() {
        return this.rtyEntries;
    }

    // convenience methods

    public void addRtyEntry(RtyEntry entry) {
        this.rtyEntries.add(entry);
    }
}

创建现在将更改为:

RtyEntry entry1 = new RtyEntry("wpn", "dd");
List<RtyEntry> entries = Arrays.asList(entry1, ...);
newdatamap.put("B1", new ABC(entries));

然后您也可以像这样分配新条目:

newdatamap.get("B1").addRtyEntry(new RtyEntry("wpfnb", "ww"));

检索条目也改为重构:

ABC data = newdatamap.get("B1");
List<RtyEntry> entries = data.getRtyEntries();
for (RtyEntry entry : entries) {
    System.out.println(entry.getName() + " has a rate of: " + entry.getRate());
}

当然您也可以通过以下方式直接检索列表:

List<RtyEntry> entries = newdatamap.get("B1").getRtyEntries();

和以前一样。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多