ArrayList(续)
删除
删除的是下标,还是元素值?答案是都有可能。
我们来看ArrayList的两个重载版本。
remove(int index) //按下表删除,并返回被删除的元素。
remove(Object o) //暗元素只删除第一个匹配项,并返回是否删除成功(有返回值)。
比如remove(1)表示删除索引为1的位置,并且让后面元素的往前挪。
那么,如果我要删除数字1本身(也就是这个ArrayList里含1的第一个位置)怎么办呢?就需要明确传入一个Integer对象nums.remove(Integer.valueOf(1))
java
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> numbers=new ArrayList<>();
numbers.add(10);
numbers.add(20);
numbers.add(30);
numbers.add(20);
boolean removed=numbers.remove(Integer.valueOf(20));
System.out.println("Element removed: " + removed);
System.out.println("Updated ArrayList: " + numbers);
}
}
而对于字符串列表等就可以直接写names.remove("奶龙")。
说到这里我们还需要注意一个点,循环删除内容时需要小心元素向前移动的问题。
java
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> numbers=new ArrayList<>();
numbers.add(10);
numbers.add(20);
numbers.add(30);
for(int i=0;i<numbers.size();i++){
if(numbers.get(i)<25){
numbers.remove(i);
}
}
}
}
这样写只会删掉10,不会删掉20,因为执行remove后20的下标变成0,而原先的i已经过掉0了。
所以合适的解决方法有两个:在后面写i--,或者从i=numbers.size()-1开始i--倒序遍历到0。
综合运用
java
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Student> students = new ArrayList<>();
Student a=new Student("小明", 90);
students.add(a);
students.add(new Student("小红", 85));
for(Student s:students){
s.showInfo();
if(s.getName().equals("小红")){
s.setScore(95);
}
}
}
}
class Student {
private String name;
private int score;
Student(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public int getScore() {
return score;
}
public int setScore(int score) {
this.score = score;
return score;
}
public void showInfo() {
System.out.println("姓名:" + name + ",成绩:" + score);
}
}
HashMap
通过键查找值的集合,用途接近C++中的unordered_map。(ArrayList是根据键取值)。
创建添加查询
java
import java.util.HashMap;
public class Main {
public static void main(String[] args) {
HashMap<String, Integer> scores = new HashMap<>();
scores.put("小明", 90);
scores.put("小红", 85);
System.out.println("小明的成绩: " + scores.get("小明"));
System.out.println("小红的成绩: " + scores.get("小红"));
}
}
这里有两个泛型参数,键的类型和值的类型都是泛型的。读取用get(),添加或修改用put()。
键不能重复,重复put会替换值。比如:
scores.put("小明", 100);
scores.put("小明", 90);
System.out.println(scores.get("小明")); //90
System.out.println(scores.size()); //1
键不存在时,get()返回null,null表示没有任何引用对象。
System.out.println(scores.get("小李"));
null表示没有引用任何对象,这里返回的类型是Integer,所以能够返回null。但是如果:
int score=scores.get("小李");
这在运行时会抛出NullPointerException:Java想把Integet自动拆箱成int,但是拿到的却是null。
int score=scores.getOrDefault("小李",0);
System.out.println(score); //0
这样就对了。getOrDefault只会返回默认值,不会把键添加进Map。
常用操作
scores.containsKey("小明"); // 判断是否存在这个键
scores.remove("小明"); // 删除这个键及对应的值
scores.size(); // 键值对数量
scores.isEmpty(); // 是否为空
java
for (String name : scores.keySet()) {
System.out.println(name + ": " + scores.get(name));
}
其中keySet()返回所有键组成的集合(也就是键这一列)。
HashMap不保证遍历顺序,不能依赖它按照添加顺序输出。
实例
再次注意:键不能重复,重复则put会替换值。
练习之计数问题:
java
import java.util.HashMap;
public class Main {
public static void main(String[] args) {
int[] nums = {2,3,2,5,3,2};
HashMap<Integer, Integer> map = new HashMap<>();
for(int num:nums){
map.put(num,map.getOrDefault(num, 0)+1);
}
System.out.println(map);
}
}
练习之常见函数
java
import java.util.HashMap;
public class Main {
public static void main(String[] args) {
HashMap<String, Integer> map =new HashMap<>();
map.put("A",10);
map.put("B",20);
map.put("A",30);
int x=map.getOrDefault("C",0);
System.out.println(map.get("A"));
System.out.println(x);
System.out.println(map.size());
}
}
答案是30 0 2,这里最重要的就是put会覆盖原来的值,以及getOrDefault不会把键添加给Map。
HashSet
保存不重复元素的集合,用途接近C++的unordered_set。
创建添加删除查找
java
import java.util.HashSet;
public class Main {
public static void main(String[] args) {
HashSet<Integer> nums = new HashSet<>();
System.out.println(nums.add(10)); // true:添加成功
System.out.println(nums.add(20)); // true
System.out.println(nums.add(10)); // false:已经存在,不重复添加
System.out.println(nums.size()); // 2
System.out.println(nums.contains(10)); // true
nums.remove(10);
System.out.println(nums.contains(10)); // false
}
}
注意方法名的区别:
map.containsKey(key); // HashMap:判断键是否存在
set.contains(value); // HashSet:判断元素是否存在
下标问题
HashSet没有下标,也不保证遍历顺序。
因此HashSet的remove(10)是删除数值10,不会像ArrayList那样当成下标,因为没有按下标删除的重载。
也可以用for(int num:nums)来遍历,但不能依赖输出顺序与添加顺序相同。
去重问题
HashSet<String> name=new HashSet<>();
name.add(new String("小明"));
name add(new String("小明"));
System.out.println(names.size()); //1
虽然创建了两个不同的字符串对象,但是HashSet判断重复会结合元素的hashCode()和equals()。
实例
判断是否重复
java
public static boolean hasDuplicate(int[] nums) {
HashSet<Integer> set=new HashSet<>();
for(int num:nums) {
if(set.contains(num)){
return true;
}
set.add(num);
}
return false;
}
中间的if也可以写成if(!set.add(num)),因为添加会返回值,如果添加失败给出0,说明这个数字之前出现过。
练习
java
import java.util.HashSet;
public class Main {
public static void main(String[] args) {
HashSet<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
set.add(1);
boolean a=set.remove(1);
boolean b=set.remove(1);
System.out.println(a); // true
System.out.println(b); // false
System.out.println(set.size()); // 1
}
}