Map
基本操作:
public class Test {
public static void main(String[] args) {
Random rand = new Random();
Map<Integer, Integer> m =
new HashMap<>();
for (int i = 0; i < 10000; i++) {
int r = rand.nextInt(20);
// get(key)方法获取键的值
Integer freq = m.get(r);
// freq为null时,说明该键第一次被找到,所以将freq赋为1
m.put(r, freq == null ? 1 : ++freq);
}
println(m);
}
}
把一个对象映射到另一个对象:
public static void basicOp2() {
var petMap = new HashMap<String, Pet>();
petMap.put("My cat", new Cat("Nick"));
petMap.put("My dog", new Dog("gystyle"));
petMap.put("My Hamster", new Hamster("Anal"));
println(petMap);
Pet dog = petMap.get("My dog");
println(dog);
}
Map也可以扩展到多维;先清楚:
- List<? extends Pet> 代表传入的类型是Pet本身或者其子类,代表着传入类型上界;
- List<? super Pet> 代表传入的类型是Pet本身或者其父类,代表着传入类型下界。
Map可以返回包含它的所有键的Set,以及包含它的所有值的Collection。
public static void basicOp3() {
var petOwner =
new HashMap<Person, List<? extends Pet>>();
petOwner.put(new Person("Dawn"),
Arrays.asList(new Cymric("Molly"), new Mutt("Spot")));
petOwner.put(new Person("Kate"),
Arrays.asList(new Cat("Shackleton"), new Cat("Elsie")));
petOwner.put(new Person("Marilyn"),
Arrays.asList(new Pug("Fuck"), new Cat("Isaac")));
println("People: " + petOwner.keySet());
println("Pets: " + petOwner.values());
// 以所有的键为set即[person1, person2]
for (Person person : petOwner.keySet()) {
println(person + " has");
// 以键为索引获取值的Collection即person=[pet1, pet2]
for (Pet pet : petOwner.get(person))
println(" " + pet);
}
}
使用set和map来跟踪字母
public static void vowelCounter(Set<String> st) {
// 记录元音字母以做比较
var vowels = new TreeSet<Character>();
Collections.addAll(vowels,
'A', 'E', 'I', 'O', 'U', 'a', 'e', 'i', 'o', 'u');
int sumVowels = 0;
// 为遍历单词作准备,核心语句
var vowelMap =
new TreeMap<Character, Integer>();
// 逐个遍历
for (String s : st)
for (Character v : s.toCharArray())
if (vowels.contains(v)) {
Integer count = vowelMap.get(v);
// 查询自增基本形式:
vowelMap.put(v, count == null ? 1 : ++count);
sumVowels++;
}
println("Vowels: " + vowelMap);
println("Total vowels: " + sumVowels);
}
映射经典题,先认识下Map.Entry接口,记录键值对;Map.entrySet() 这个方法返回的是一个Set<Map.Entry<K,V>>,而Set<Map.Entry<K,V>>表示一个映射项的Set,而Map.Entry有getValue()和getKey().
public class Train2 {
public static int getBestInt20(int n) {
Random rand = new Random();
Map<Integer, Integer> m =
new TreeMap<>();
// 单个测试重复生成0~19的数字n次
for(int i = 0; i < n; i++) {
// Produce a number between 0 and 20:
int r = rand.nextInt(20);
Integer freq = m.get(r);
m.put(r, freq == null ? 1 : ++freq);
}
// 单个测试中找出出现频率最高的数字的值
int max = 0;
for(int i = 0; i < m.keySet().size(); i++) {
max = max < m.get(i) ? m.get(i) : max;
}
// Map.Entry记录键值对。
// 传入m.entrySet参数,Map.Entry有getKey,getValue方法
// findMax是一个键值对,me则是一组键值对
Set<Map.Entry<Integer, Integer>> me = new
LinkedHashSet<>(m.entrySet());
int maxKey = 0;
// 单个测试中找出出现频率最高的数字
for (Map.Entry<Integer, Integer> findMax : me) {
if (findMax.getValue() == max)
maxKey = findMax.getKey();
}
return maxKey;
}
public static void main(String[] args) {
Map<Integer, Integer> m20 =
new TreeMap<>();
// 进行2000次测试
for(int i = 0; i < 2000; i++) {
int x = getBestInt20(10000);
// 这次变成记录出现频率最大的数字 的出现频率
Integer freq = m20.get(x);
m20.put(x, freq == null ? 1 : ++freq);
}
println("Most often picked ints, 0 - 19, in 2000 tests of 10,000 random picks: ");
println(m20);
}
}
使用映射来提取键值对,排序后再存入
public static void main(String[] args) {
Map<String, Integer> m = new LinkedHashMap<>();
m.put("ten", 10);
m.put("nine", 9);
m.put("eight", 8);
m.put("seven", 7);
m.put("six", 6);
m.put("five", 5);
m.put("four", 4);
m.put("three", 3);
m.put("two", 2);
m.put("one", 1);
m.put("zero", 0);
println("Sort: " + m);
// extract out .
Map<String, Integer> mTemp = new LinkedHashMap<>();
Set<String> ss = new TreeSet<>(m.keySet());
for (String s: ss) {
Integer i = m.get(s);
m.remove(s);
mTemp.put(s, i);
}
// store in
for (String s : ss) {
Integer i = mTemp.get(s);
mTemp.remove(s);
m.put(s, i);
}
mTemp.clear();
println("Sorted map: " + m);
}
多维数组题:先了解下值更新:
public static void main(String[] args) {
Map<String, ArrayList<Integer>> map = new LinkedHashMap<>();
var a = new ArrayList<Integer>();
a.add(1);
map.put("fuck", a);
println(map); // {fuck=[1]}
a.add(2);
map.put("fuck", a);
println(map); // {fuck=[1,2]}
}
public class Test {
public static void main(String[] args) {
Map<String,ArrayList<Integer>> m = new LinkedHashMap<>();
List<String> words = new LinkedList<>(Arrays.asList("fuck", "shit", "fuck", "fuck", "shit", "anal"));
System.out.println("Words in file: " + words);
Iterator<String> itWords = words.iterator();
int index = 0;
while(itWords.hasNext()) {
String s = itWords.next();
index++; // 每次循环都自增表示位置
// 即第一次加入单词,在第一个位置插入index
if(!m.containsKey(s)) {
ArrayList<Integer> ai = new ArrayList<>();
ai.add(0, index);
m.put(s, ai);
}
else {
// 找出s的值,并把index加入到对应的键的值里面
m.get(s).add(index);
// 更新字典,将新的数组赋给s
m.put(s, m.get(s));
}
}
println("Map of word locations: " + m);
}
}
总结List
遍历List的四种方法
Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");
//第一种:普遍使用,二次取值
System.out.println("通过Map.keySet遍历key和value:");
for (String key : map.keySet()) {
System.out.println("key= "+ key + " and value= " + map.get(key));
}
//第二种
System.out.println("通过Map.entrySet使用iterator遍历key和value:");
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第三种:推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第四种
System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
for (String v : map.values()) {
System.out.println("value= " + v);
}