Java二维数组排序以及接口Comparator的使用

刚学习Java一个月,对于一些东西不是很熟悉,今天在刷题时候时候,需要对多维数组中的某维进行升序/降序排列,思考到这个问题,开始百度学习如何解决!!!
文章内容参考了以下的博客:

https://blog.csdn.net/u012250875/article/details/55126531
https://www.cnblogs.com/wwjj4811/p/12828986.html
https://blog.csdn.net/lx_nhs/article/details/78871295
https://www.cnblogs.com/tigerlion/p/10700167.html
https://blog.csdn.net/weixin_43836046/article/details/100164220

二维数组降维

常用类Arrays中有个sort()方法,可以对数组进行默认的升序排列:

public class Solution {
    public static void main(String[] args) {
        int[] nums=new int[]{6,7,8,9,1,0,24,6,7};
        Arrays.sort(nums);
        System.out.println(Arrays.toString(nums));
    }
}

输出:

[0, 1, 6, 6, 7, 7, 8, 9, 24]

但是貌似对于基本类型没有直接的降序API可以调用,要么自己写,要么将基本类型转换对应的包装类!
首先介绍如何将int数组转换成Integer数组

public class Solution {
    public static void main(String[] args) {
        int[] nums=new int[]{6,7,8,9,1,0,24,6,7};
//        //首先将int数组转为数值流
//        IntStream stream=Arrays.stream(nums);
//        //将流中的所有元素装箱,转换为流--->int转为integer
//        Stream<Integer> integerStream=stream.boxed();
//        //将流转换为数组
//        Integer[] integers=integerStream.toArray(Integer[]::new);
        //以上三步可以合成一步来写
        Integer[] integers=Arrays.stream(nums).boxed().toArray(Integer[]::new);
        System.out.println(Arrays.toString(integers));
        System.out.println(integers instanceof Integer[]);
        //在JAVA8中可以使用Lambda表达式简化代码,实现降序
        Arrays.sort(integers,((o1, o2) -> o2-o1));
        System.out.println(Arrays.toString(integers));
    }
}

输出:

[6, 7, 8, 9, 1, 0, 24, 6, 7]
true
[24, 9, 8, 7, 7, 6, 6, 1, 0]

上面我们成功的将int[]数组转为Integer[]数组
我们使用Arrays中sort()函数的重载版:

Arrays.sort(T[], new Comparator<T>() {//Comparator<T>中的T需要引用类型,基本类型使用不了
	public int compare(T a, T b){
		return a - b;
	}
});

对数组进行降序排列

public class Solution {
    public static void main(String[] args) {
        int[] nums=new int[]{6,7,8,9,1,0,24,6,7};
        Integer[] integers=Arrays.stream(nums).boxed().toArray(Integer[]::new);
        Arrays.sort(integers, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;
            }
        });
        System.out.println(Arrays.toString(integers));
    }
}

输出:

[24, 9, 8, 7, 7, 6, 6, 1, 0]

ok,完成了我们的第一步。下面我们实现二维数组的某维的降序排列

public class Solution {
    public static void main(String[] args) {
        int[][] nums=new int[][]{{6,7},{8,9},{1,0},{24,6},{7,8}};
        //对第一维进行排序
        Arrays.sort(nums, new Comparator<int[]>() {//这里int[]就是每一维数组的引用,可以直接使用
            @Override//重写比较函数,只比较第一维
            public int compare(int[] o1, int[] o2) {
                return o1[0]-o2[0];//0代表第一维
            }
        });
        //输出数组
        for (int i=0;i<nums.length;i++){
            System.out.println(Arrays.toString(nums[i]));
        }
    }
}

输出:

[1, 0]
[6, 7]
[7, 8]
[8, 9]
[24, 6]

可以看出,效果达到了我们的目的。这个时候又有一个问题,是否可以让多维函数同时降维,当然可以,只需要像上面重复几次,但是如果每个维度中的值,存在关系,比如(数组索引i的处的值和索引I),这个时候就不能乱来,只有当主维度(这个自己设定哪一维为主维)相同时,再对其他维排序!
表达能力不是很好,看一段程序就明白了:

public static void main(String[] args) {
	int[][] nums = new int[][]{{1,3},{1,2},{4,5},{3,7}};
	Arrays.sort(nums, new Comparator<int[]>() {
		public int compare(int[] a, int[] b){
			if(a[0]==b[0]){//当第一维值相同,比较第二维(一维为主维)
				return a[1] - b[1];
			}else {
				return a[0] - b[0];//当第一维值不同,按第一维值排序
			}
		}
	});
	for(int i=0;i<nums.length; i++){
		System.out.println(Arrays.toString(nums[i]));
	}

输出:

[1, 2]
[1, 3]
[3, 7]
[4, 5]

Comparator接口

上面的程序都用到了Comparator这个接口,介绍一下这个接口的使用。

  • Comparator是java.util下的一个接口,该接口抽象度极高,有必要掌握该接口的使用
  • 很多时候,大家都用这个接口来实现排序功能,但是它可以做的事情不单单是排序

接口功能:该接口代表一个比较器,比较器具有可比性,javaSE中数组的工具类和集合工具类提供的sort()方法就是Comparator接口来处理排序的!下面是JavaSE一些使用到Comparator接口的地方:

Arrays.sort(T[],Comparator<? super T> c);
Collections.sort(List<T> list,Comparator<? super T> c);

使用场景
什么场景下需要做比较,那么什么场景下就有Comparator接口的用处,主要为两个场景:

  • 排序,需要比较谁在前,谁在后(排序也可以让类实现Comparable接口,实现后该类的实例也具有排序能力)
  • 分组,需要比较两个对象是否属于同一组

举例说明:

1、排序
在List或数组中的对象如果没有实现Comparator接口时,那么就需要调用者为需要排序的数字或者list设置一个Comparator,通过重写Comparator接口中compare()函数来设置比较规则进行排序。

public class Solution {
    class Dog{
        public int age;
        public String name;
        public Dog(int m_age,String m_name){
            age=m_age;
            name=m_name;
        }

        @Override
        public String toString() {
            return "Dog [age="+age+",name="+name+"]";
        }
    }
    public static void main(String[] args) {
        List<Dog> list=new ArrayList<Dog>();
        list.add(new Solution().new Dog(7,"DogA"));
        list.add(new Solution().new Dog(5,"DogB"));
        list.add(new Solution().new Dog(6,"DogC"));

        Collections.sort(list, new Comparator<Dog>() {
            @Override
            public int compare(Dog o1, Dog o2) {
                return o1.age-o2.age;
            }
        });
        System.out.println("给狗狗按年龄升序排序: "+list);
        Collections.sort(list, new Comparator<Dog>() {
            @Override
            public int compare(Dog o1, Dog o2) {
                return o1.name.compareTo(o2.name);
            }
        });
        System.out.println("给狗狗按name字典升序排序: "+list);
    }
}

分组:
使用Comparator和for循环处理处理列表,来进行分类;通过调用者实现Comparator接口的比较逻辑,来告诉程序怎么比较,通过比较之后的结果来进行分组。比如生活中的拳击比赛,会有公斤级的概念,那么程序中应该实现的处理逻辑是只要两个人的体重在同一个区间则为同一组公斤级的选手。下面的例子中分别按照狗狗颜色和体重两个维度进行分组,分组的核心逻辑其实就是比较。于是抽象了一个工具方法:dividerList,第一个参数为需要处理的数据源,第二个参数就是分组的比较逻辑

public class Solution {
    class Apple {
        public String color;
        public int weight;

        public Apple(String m_color, int m_weight) {
            color = m_color;
            weight = m_weight;
        }

        @Override
        public String toString() {
            return "Apple[color=" + color + ",wieght=" + weight + "]";
        }
    }
        public static <T> List<List<T>> divider(Collection<T> datas, Comparator<? super T> c) {
            List<List<T>> result = new ArrayList<List<T>>();
            for (T t : datas) {
                boolean isSameGroup = false;
                for (int j = 0; j < result.size(); j++) {
                    if (c.compare(t, result.get(j).get(0)) == 0) {
                        isSameGroup = true;
                        result.get(j).add(t);
                        break;
                    }
                }
                if (!isSameGroup) {
                    // 创建
                    List<T> innerList = new ArrayList<T>();
                    result.add(innerList);
                    innerList.add(t);
                }
            }
            return result;
        }

        public static void main(String[] args) {
            List<Apple> list = new ArrayList<>();
            list.add(new Solution().new Apple("红", 205));
            list.add(new Solution().new Apple("红", 131));
            list.add(new Solution().new Apple("绿", 248));
            list.add(new Solution().new Apple("绿", 153));
            list.add(new Solution().new Apple("黄", 119));
            list.add(new Solution().new Apple("黄", 224));
            List<List<Apple>> byColors = divider(list, new Comparator<Apple>() {

                @Override
                public int compare(Apple o1, Apple o2) {
                    // 按颜色分组
                    return o1.color.compareTo(o2.color);
                }
            });
            System.out.println("按颜色分组" + byColors);
            List<List<Apple>> byWeight = divider(list, new Comparator<Apple>() {

                @Override
                public int compare(Apple o1, Apple o2) {
                    // 按重量级

                    return (o1.weight / 100 == o2.weight / 100) ? 0 : 1;
                }
            });
            System.out.println("按重量级分组" + byWeight);
        }
}

总结

一般需要做比较逻辑都可以使用的上Comparator,最常用的场景就是排序和分组,排序常使用Arrays和Collections的sort方法,二分组则可以使用上面提供的divider方法。

排序和分组的区别在于:
排序时,两个对象比较的结果有三种:大于,等于,小于
分组时,两个对象比较的结果只有两种:等于(两个对象属于同一组),不等于(两个对象属于不同组)

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值