同一个键下的多个值

是否有可能实现一个HashMap有一个键和两个值。就像HashMap?

请帮助我,也通过告诉(如果没有办法)任何其他方法来实现三个值的存储与一个作为关键?

656386 次浏览

不,不只是作为HashMap。你基本上需要一个HashMap从一个值的集合的键。

如果你乐于使用外部库,番石榴Multimap中就有这个概念,其实现有ArrayListMultimapHashMultimapLinkedHashMultimap等。

Multimap<String, Integer> nameToNumbers = HashMultimap.create();


System.out.println(nameToNumbers.put("Ann", 5)); // true
System.out.println(nameToNumbers.put("Ann", 5)); // false
nameToNumbers.put("Ann", 6);
nameToNumbers.put("Sam", 7);


System.out.println(nameToNumbers.size()); // 3
System.out.println(nameToNumbers.keySet().size()); // 2

是也不是。解决方案是为包含与键对应的2(3或更多)值的值构建一个Wrapper类。

你可以:

  1. 使用具有列表作为值的映射。Map<KeyType, List<ValueType>>
  2. 创建一个新的包装器类,并在映射中放置该包装器的实例。Map<KeyType, WrapperType>
  3. 使用类似类的元组(节省了创建大量包装器)。Map<KeyType, Tuple<Value1Type, Value2Type>>
  4. 同时使用多个地图。

例子

1. 以list为值的映射

// create our map
Map<String, List<Person>> peopleByForename = new HashMap<>();


// populate it
List<Person> people = new ArrayList<>();
people.add(new Person("Bob Smith"));
people.add(new Person("Bob Jones"));
peopleByForename.put("Bob", people);


// read from it
List<Person> bobs = peopleByForename["Bob"];
Person bob1 = bobs[0];
Person bob2 = bobs[1];

这种方法的缺点是列表没有绑定到恰好两个值。

2. 使用包装器类

// define our wrapper
class Wrapper {
public Wrapper(Person person1, Person person2) {
this.person1 = person1;
this.person2 = person2;
}


public Person getPerson1() { return this.person1; }
public Person getPerson2() { return this.person2; }


private Person person1;
private Person person2;
}


// create our map
Map<String, Wrapper> peopleByForename = new HashMap<>();


// populate it
peopleByForename.put("Bob", new Wrapper(new Person("Bob Smith"),
new Person("Bob Jones"));


// read from it
Wrapper bobs = peopleByForename.get("Bob");
Person bob1 = bobs.getPerson1();
Person bob2 = bobs.getPerson2();

这种方法的缺点是必须为所有这些非常简单的容器类编写大量样板代码。

3.使用元组

// you'll have to write or download a Tuple class in Java, (.NET ships with one)


// create our map
Map<String, Tuple2<Person, Person> peopleByForename = new HashMap<>();


// populate it
peopleByForename.put("Bob", new Tuple2(new Person("Bob Smith",
new Person("Bob Jones"));


// read from it
Tuple<Person, Person> bobs = peopleByForename["Bob"];
Person bob1 = bobs.Item1;
Person bob2 = bobs.Item2;

在我看来,这是最好的解决办法。

4. 多个地图

// create our maps
Map<String, Person> firstPersonByForename = new HashMap<>();
Map<String, Person> secondPersonByForename = new HashMap<>();


// populate them
firstPersonByForename.put("Bob", new Person("Bob Smith"));
secondPersonByForename.put("Bob", new Person("Bob Jones"));


// read from them
Person bob1 = firstPersonByForename["Bob"];
Person bob2 = secondPersonByForename["Bob"];

这种解决方案的缺点是,两个映射之间的关联并不明显,编程错误可能会导致两个映射不同步。

看看guava库中的Multimap及其实现——HashMultimap

类似于Map的集合,但可以将多个值与单个键关联。如果使用相同的键但不同的值调用put(K, V)两次,则multimap包含从键到两个值的映射。

我无法回复Paul的评论,所以我在这里为Vidhya创建了新的评论:

包装器将是我们想存储为值的两个类的SuperClass

在包装器类内部,我们可以将这些关联作为两个类对象的实例变量对象。

如。

class MyWrapper {


Class1 class1obj = new Class1();
Class2 class2obj = new Class2();
...
}

HashMap中,我们可以这样写:

Map<KeyObject, WrapperObject>

WrapperObj将有类变量:class1Obj, class2Obj

另一个不错的选择是使用Apache Commons中的MultiValuedMap。查看页面顶部的所有已知的实现类,了解专门的实现。

例子:

HashMap<K, ArrayList<String>> map = new HashMap<K, ArrayList<String>>()

可以用

MultiValuedMap<K, String> map = new MultiValuedHashMap<K, String>();

所以,

map.put(key, "A");
map.put(key, "B");
map.put(key, "C");


Collection<String> coll = map.get(key);

将导致包含"A", "B"和"C"的集合coll

我使用Map<KeyType, Object[]>将多个值与Map中的一个键关联起来。这样,我就可以存储与一个键关联的多个不同类型的值。你必须注意保持正确的插入和从Object[]中检索的顺序。

< p >的例子: 考虑一下,我们想要存储Student信息。Key是id,而我们想要存储与学生相关的姓名,地址和电子邮件
       //To make entry into Map
Map<Integer, String[]> studenMap = new HashMap<Integer, String[]>();
String[] studentInformationArray = new String[]{"name", "address", "email"};
int studenId = 1;
studenMap.put(studenId, studentInformationArray);


//To retrieve values from Map
String name = studenMap.get(studenId)[1];
String address = studenMap.get(studenId)[2];
String email = studenMap.get(studenId)[3];
HashMap<Integer,ArrayList<String>> map = new    HashMap<Integer,ArrayList<String>>();


ArrayList<String> list = new ArrayList<String>();
list.add("abc");
list.add("xyz");
map.put(100,list);

你可以隐式地做。

// Create the map. There is no restriction to the size that the array String can have
HashMap<Integer, String[]> map = new HashMap<Integer, String[]>();


//initialize a key chosing the array of String you want for your values
map.put(1, new String[] { "name1", "name2" });


//edit value of a key
map.get(1)[0] = "othername";
这是非常简单和有效的。 如果你想要不同类的值,你可以这样做:

HashMap<Integer, Object[]> map = new HashMap<Integer, Object[]>();

只是为了记录,纯JDK8解决方案将使用Map::compute方法:

map.compute(key, (s, strings) -> strings == null ? new ArrayList<>() : strings).add(value);

public static void main(String[] args) {
Map<String, List<String>> map = new HashMap<>();


put(map, "first", "hello");
put(map, "first", "foo");
put(map, "bar", "foo");
put(map, "first", "hello");


map.forEach((s, strings) -> {
System.out.print(s + ": ");
System.out.println(strings.stream().collect(Collectors.joining(", ")));
});
}


private static <KEY, VALUE> void put(Map<KEY, List<VALUE>> map, KEY key, VALUE value) {
map.compute(key, (s, strings) -> strings == null ? new ArrayList<>() : strings).add(value);
}

输出:

bar: foo
first: hello, foo, hello

注意,为了确保在多个线程访问此数据结构时的一致性,需要使用ConcurrentHashMapCopyOnWriteArrayList作为实例。

可以使用identityHashMap完成,条件是键比较将由==操作符完成,而不是equals()。

我更喜欢下面的方法来存储任意数量的变量,而不必创建一个单独的类。

final public static Map<String, Map<String, Float>> myMap    = new HashMap<String, Map<String, Float>>();
String key= "services_servicename"


ArrayList<String> data;


for(int i = 0; i lessthen data.size(); i++) {
HashMap<String, String> servicesNameHashmap = new HashMap<String, String>();
servicesNameHashmap.put(key,data.get(i).getServiceName());
mServiceNameArray.add(i,servicesNameHashmap);
}

我得到了最好的成绩。

你只需要创建新的HashMap

HashMap<String, String> servicesNameHashmap = new HashMap<String, String>();

for循环中。它将具有相同的效果,如相同的键和多个值。

我已经习惯了在Objective c中使用数据字典来实现这一目标,而在Java for Android中却很难获得类似的结果。我最终创建了一个自定义类,然后只做了一个自定义类的hashmap。

public class Test1 {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addview);


//create the datastring
HashMap<Integer, myClass> hm = new HashMap<Integer, myClass>();
hm.put(1, new myClass("Car", "Small", 3000));
hm.put(2, new myClass("Truck", "Large", 4000));
hm.put(3, new myClass("Motorcycle", "Small", 1000));


//pull the datastring back for a specific item.
//also can edit the data using the set methods.  this just shows getting it for display.
myClass test1 = hm.get(1);
String testitem = test1.getItem();
int testprice = test1.getPrice();
Log.i("Class Info Example",testitem+Integer.toString(testprice));
}
}


//custom class.  You could make it public to use on several activities, or just include in the activity if using only here
class myClass{
private String item;
private String type;
private int price;


public myClass(String itm, String ty, int pr){
this.item = itm;
this.price = pr;
this.type = ty;
}


public String getItem() {
return item;
}


public void setItem(String item) {
this.item = item;
}


public String getType() {
return item;
}


public void setType(String type) {
this.type = type;
}


public int getPrice() {
return price;
}


public void setPrice(int price) {
this.price = price;
}


}
我们可以创建一个类来拥有多个键或值,该类的对象可以用作map中的参数。 你可以引用https://stackoverflow.com/a/44181931/8065321

最简单的方法是使用谷歌集合库:

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;


public class Test {


public static void main(final String[] args) {


// multimap can handle one key with a list of values
final Multimap<String, String> cars = ArrayListMultimap.create();
cars.put("Nissan", "Qashqai");
cars.put("Nissan", "Juke");
cars.put("Bmw", "M3");
cars.put("Bmw", "330E");
cars.put("Bmw", "X6");
cars.put("Bmw", "X5");


cars.get("Bmw").forEach(System.out::println);


// It will print the:
// M3
// 330E
// X6
// X5
}


}

maven链接:https://mvnrepository.com/artifact/com.google.collections/google-collections/1.0-rc2

更多关于这个:http://tomjefferys.blogspot.be/2011/09/multimaps-google-guava.html

如果你使用Spring框架。有:org.springframework.util.MultiValueMap

创建不可修改的多值映射:

Map<String,List<String>> map = ...
MultiValueMap<String, String> multiValueMap = CollectionUtils.toMultiValueMap(map);

或者使用org.springframework.util.LinkedMultiValueMap

使用Java收集器

// Group employees by department
Map<Department, List<Employee>> byDept = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));

你的钥匙在哪个部门

 import java.io.*;
import java.util.*;


import com.google.common.collect.*;


class finTech{
public static void main(String args[]){
Multimap<String, String> multimap = ArrayListMultimap.create();
multimap.put("1","11");
multimap.put("1","14");
multimap.put("1","12");
multimap.put("1","13");
multimap.put("11","111");
multimap.put("12","121");
System.out.println(multimap);
System.out.println(multimap.get("11"));
}
}

输出:

     {"1"=["11","12","13","14"],"11"=["111"],"12"=["121"]}


["111"]

这是用于实用功能的Google-Guava库。这就是需要的解决方案。

Apache Commons集合类可以在同一个键下实现多个值。

MultiMap multiMapDemo = new MultiValueMap();


multiMapDemo .put("fruit", "Mango");
multiMapDemo .put("fruit", "Orange");
multiMapDemo.put("fruit", "Blueberry");


System.out.println(multiMapDemo.get("fruit"));

Maven的依赖

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>