java问题,我想在java中存储键值对,以便使用,但是键值对的键和值都有重复元素,使用hashmap会产生覆盖。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java问题,我想在java中存储键值对,以便使用,但是键值对的键和值都有重复元素,使用hashmap会产生覆盖。相关的知识,希望对你有一定的参考价值。

比如下列数据:
a,1;
b,2;
c;2;
a,4;
每组都是所需要的,键和值都有重复,所以键值调换也不行。所以hashmap也许行不通。问下大家有什么解决办法,
1,或者hashmap我有不知道的可以实现的方法,
2,或者数据结构中学过的链表如何实现,请大家指导一下,
3,或者有java中其他方法实现,
感激不尽,会加分的。
谢谢大家。只要能实现get一个key得到一个对应的value就好,我再试试。

你这个是n vs n的情况,都不算算是键值对应关系了。所以不用考虑map了
链表和这个也没有太大关系,主要有多对多的情况

不知道你那个
b 2
c 2是不是有序的,如果有序的话,用数组可以简单实现
参考技术A 用二维数组是可以的,但是你也知道,数组的量是固定的,所以不怎么方便,所以还是要用一些容器,就像类似与上面的所说先建立一个专门存放数据的类,
class map2<K,V>//泛型,填写你想要的数据类型

private K key;
private V value;
public map2(K k2,V v2)key=k2;value=v2; //初始化key和value
public K getKey()return key;
public V getValue()return value;
public void setKey(K key2)this.key=key2;
public void setValue(V value2)this.value=value2;

然后就可以用ArrayList arr=new ArrayList()来添加任意的键值对应的数据了,
当然每次添加都要先map2<object,object> bb=new map2<object,object>();object根据你的实际需要填写不同的数据类型,实在不爽就直接填object吧,arr.add(bb);...........本回答被提问者采纳
参考技术B 只是简单的存的话 定义一个类型
class KV
Object key;
Object value;

然后你想用啥数据结构就用吧 比如ArrayList<KV>- -

楼主 如果你想get一个key对应一个value 但你的key本身就不惟一 你如何只get一个key就拿到一个惟一对应的value?
参考技术C 是的,可以考虑用二维数组。
String[][] array2 = new String[10][10];
array2 [0][0] = "a"; array2 [0][1] = "1";
array2 [1][0] = "b"; array2 [1][1] = "2";
array2 [2][0] = "c"; array2 [2][1] = "2";
array2 [3][0] = "a"; array2 [3][1] = "4";
参考技术D 用个二维数组。

在 Java 中使用并发在磁盘上创建键值存储

【中文标题】在 Java 中使用并发在磁盘上创建键值存储【英文标题】:Creating a Key-Value Store on Disc with Concurrency in Java 【发布时间】:2011-10-19 08:43:33 【问题描述】:

我需要读取一组文件并将其分解为键值对,并将它们保存为磁盘上该键的(键、值列表),就像 map-reduce 范例一样。一切都在一台计算机上。例如,我可以在不同的文件上编写不同的列表并用密钥命名文件。这似乎是一种非常糟糕的做事方式。首先,如果你有十亿个密钥,你最终会得到十亿个文件。所以很明显那是行不通的,我需要某种内存映射。我还必须让不同的线程来执行映射工作,所以如果它们要写入同一个缓冲区,它们之间就必须进行某种同步。如果我有一个键值缓冲区映射,并在缓冲区上同步,那么线程不应该互相踩踏,所以我认为这部分应该可以工作。问题是如何将值映射到光盘。如何在同一个文件中写入对应于不同键的缓冲区?如果有人能指出我正确的方向,将不胜感激。我对这方面的了解非常可悲。再次感谢。

【问题讨论】:

您实际上想要做什么?应用程序是什么?你谈论缓冲和并发,但并没有真正给出一个理由来解决这个问题(这使得你很难理解你为什么要提出这些问题。)你真的有十亿个键吗?还是一百万?这是您尝试做的实际要求吗? 我不能说应用程序到底是什么,但它与在单机上编写 MapReduce 非常相似。从文件中读取输入,将其分解为键值对,然后收集特定键的值。所有步骤都必须在磁盘上完成,因为数据包含在数十亿个密钥中。数十亿,而不是数百万。 @delmet,我不明白你为什么需要“键值缓冲区映射”?值已经映射到键...如何映射缓冲区?无论如何,请参阅我的答案以获取更多详细信息。 【参考方案1】:

Chronicle Map应该是解决这个问题的好方法。

通常它在操作速度和消耗的内存方面都非常有效,即。 e.它是 much faster,而不是之前建议的 BerkeleyDB。

Chronicle Map 是一种分段存储,允许并行处理分段,例如。克:

for (int i = 0; i < chronicleMap.segments(); i++) 
  int segmentIndex = i;
  executor.submit(() -> 
    chronicleMap.segmentContext(segmentIndex).forEachSegmentEntry(entry -> 
      // do processing with entry.key() and entry.value(),
      // value() could be a List or some Iterator-like abstraction
    );
  );

MapSegmentContext Javadocs。

但是,每个键 could not always be handled efficiently with Chronicle Map 具有(逻辑上)多个值。但是在您的情况下,如果您只需要处理每个键的静态值集,而不是添加/删除值,它可能会很好。

【讨论】:

【参考方案2】:

你看过使用Hadoop吗?

【讨论】:

【参考方案3】:

从实际的角度来看,使用 BerkeleyDB 很容易做到这一点,as Lirik suggested.

如果您对理论比对实践更感兴趣,我建议您将其视为“外部排序”操作。也就是说,将尽可能多的输入读入内存,然后按键排序。将已排序的块写为单个文件。然后可以轻松地将排序后的文件合并到一个文件中。

在其他应用程序中,这是 Lucene 用来构建“倒排索引”以搜索文本的方法。 “键”是文档中的单词,“值”是出现该单词的文档列表。 Lucene 读取文档,并为每个单词在内存中创建一个术语到文档的条目。当内存已满时,它将索引段写入磁盘。当磁盘上有很多索引段时,将它们合并为一个段。事实上,您也可以根据您的任务调整 Lucene 的索引编写器。

可以将工作划分为多个线程。但是,您必须对磁盘争用敏感。跳过同时读取和写入许多文件会大大降低传统驱动器的速度。可能有机会同时安排一些活动。当您将前一个已排序的块写入磁盘时,您可能会从一个文件中读取新数据,尤其是在机器有两个磁盘驱动器的情况下。当然,使用 SSD 临时存储一些已排序的段会很有帮助。

【讨论】:

当他说“如何实现磁盘上的键值映射”时,这就是他要问的吗?无论如何,是的,这正是你要做的!另一件要提的是,一旦你进行了外部排序,你就可以用段的内容更新数据库并摆脱段。 是的,这就是我所说的。对不起,不够清楚。这也是我相信在 Hadoop 中完成事情的方式,以及为什么密钥需要具有可比性。我想知道天气只能一步完成,但我认为这是不可能的。您需要排序和合并。【参考方案4】:

我认为Oracle's Berkeley DB 可能正适合你:

Berkeley DB 旨在将数据存储为键/值对中数据的不透明字节数组,这些数据以可用访问方法之一为索引,如上所示。

Berkeley 非常健壮、成熟且快速,但如果您想采用更轻量级的方法,请使用SQLite。

另一种选择是使用 Google 的 LevelDB;它是用 C++ 编写的,但有 Java wrappers around it。 LevelDB 速度快得令人麻木,而且非常轻量级!

没有更多关于你的项目的细节,我只能说:

使用所有这些解决方案,键/值对将存储在同一个文件中(如有必要,多个实例可以存储到单独的文件中,但我不明白为什么会这样)。 BerkeleyDB 和 LevelDB 具有非常好的缓存和映射功能。 BDB 和 LDB 也允许压缩(不确定 SQLite 是否也支持)。 根据您的密钥分布(即,如果您使用像 Google 的 CityHash 这样的良好哈希函数),您可能会获得非常好的数据局部性,从而减少表扫描。 您可能应该编写自己的线程安全缓冲区,并且应该避免让多个线程写入 BDB/LDB,因为这些解决方案是基于磁盘的,并且您通常不希望进行多线程磁盘 I/O 操作。

评论: - 我不确定您所说的“键值缓冲区映射”是什么意思......您是否将缓冲区映射到每个键?为什么需要它?

【讨论】:

这肯定行得通,但如果可以完成磁盘上的键值映射,那就太好了。我想这不是一个小问题。 @delmet 我不确定我是否理解您在这里的要求:值作为数据库底层结构的一部分映射到键,并且数据库存储在磁盘上(不在记忆)。插入、更新、读取等都是在给定的键上完成的。磁盘上的键值映射是在将值映射到键时完成的。这有意义吗? 我说的是上面的 Ericson 说的是什么。在那里看到我的评论。感谢您的帮助。

以上是关于java问题,我想在java中存储键值对,以便使用,但是键值对的键和值都有重复元素,使用hashmap会产生覆盖。的主要内容,如果未能解决你的问题,请参考以下文章

“key”是不是在 Java HashMap 中存储了两次?

使用 shell 脚本迭代 json 以存储键值对

存储键值对的最佳 Java 数据结构 [重复]

java:我想使用键值对,并且键或者值可以重复,在java中找得到对应的类吗?

Java的HashMap键值对存储结构解析

如何在 Flutter 中创建和读取一组键值对(映射)以在 Firestore 中存储数据