Set排序方法

在讲解Set集合排序的几种方法之前,我们应该先清楚Set集合的几种类型以及特点,才能有效使用起来。

Set集合的特点

​ Set不允许包含相同的元素,如果试图把两个相同元素加入同一个集合中,add方法返回false。
​ Set判断两个对象相同不是使用==运算符,而是根据equals方法。也就是说,只要两个对象用equals方法比较返回true,Set就不会同时接受这两个对象

Set集合的分类

Set集合主要分为3种:

​ |——SortedSet接口——TreeSet实现类

Set接口——|——HashSet实现类

​ |——LinkedHashSet实现类

  • HashSet(无序,可null)

HashSet的特点是不能保证元素的排列顺序,顺序有可能发生变化,集合元素可以是null,但只能放入一个null。因为在HashSet中存入一个元素的时候,会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置,所以储存位置是随机的。HashSet就好像是HashMap的key。

  • TreeSet(有元素顺序的)

TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序 和定制排序,其中自然排序为默认的排序方式。一般的Set排序都会使用到TreeSet。

  • LinkedHashSet(记录插入顺序)

LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起 来像是以插入顺 序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。一般的,如果让你设计一个缓存算法,LinkedHashSet就是基本的基础,利用LRU,筛选出应该淘汰的元素。

由于TreeSet是有元素顺序的,因此我们在排序的过程中都会使用TreeSet。

方法一:传统方法

public class TraditionalSetSortTest {
    public static void main(String[] args) {
        Set<BigDecimal> set = new HashSet<>();
        set.add(new BigDecimal(1.2).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(2.3).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(3.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(2.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(0.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(9.4).setScale(2, BigDecimal.ROUND_HALF_UP));

        TreeSet<BigDecimal> sortSet = new TreeSet<>(new Comparator<BigDecimal>() {
            @Override
            public int compare(BigDecimal o1, BigDecimal o2) {
                return o1.compareTo(o2);
            }
        });
        sortSet.addAll(set);
        System.out.println(sortSet);
    }
}
--------------------------------------------------------------------------------------------
结果:[0.40, 1.20, 2.30, 2.40, 3.40, 9.40]

方法二:lambda表达式

public class LambdaSetSortTest {
    public static void main(String[] args) {
        Set<BigDecimal> set = new HashSet<>();
        set.add(new BigDecimal(1.2).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(2.3).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(3.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(2.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(0.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(9.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        TreeSet<BigDecimal> sortedSet = new TreeSet<>(((o1, o2) -> o1.compareTo(o2)));
        sortedSet.addAll(set);
        System.out.println(sortedSet);
    }
}
--------------------------------------------------------------------------------------------
结果:[0.40, 1.20, 2.30, 2.40, 3.40, 9.40]

方法三:使用Comparator,在jdk1.8以后,Comparator有Comparator.naturalOrder()自然排序这个方法,也有Comparator.reverseOrder()相反排序的方法。

public class ComparatorSetSortTest {
    public static void main(String[] args) {
        Set<BigDecimal> set = new HashSet<>();
        set.add(new BigDecimal(1.2).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(2.3).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(3.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(2.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(0.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(9.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        TreeSet<BigDecimal> sortedSet = new TreeSet<>(Comparator.naturalOrder());
        sortedSet.addAll(set);
        System.out.println(sortedSet);
    }
}
--------------------------------------------------------------------------------------------
结果:[0.40, 1.20, 2.30, 2.40, 3.40, 9.40]

方法四:使用Stream

这里使用Stream的时候可以转还成Set或者List,转换成Set的时候还需要再创建TreeSet,如果没有必须要求是Set,其实可以是直接转换成List,直接就是有序的,更加方便。

List list = set.stream().sorted(Comparator.naturalOrder()).collect(Collectors.toList());
public class StreamSetSortTest {
    public static void main(String[] args) {
        Set<BigDecimal> set = new HashSet<>();
        set.add(new BigDecimal(1.2).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(2.3).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(3.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(2.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(0.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(9.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        Set newSet = set.stream().sorted(Comparator.naturalOrder()).collect(Collectors.toSet());
        TreeSet<Object> treeSet = new TreeSet<>();
        treeSet.addAll(newSet);
        System.out.println(treeSet);
    }
}
--------------------------------------------------------------------------------------------
结果:[0.40, 1.20, 2.30, 2.40, 3.40, 9.40]
补充:

已知数值a,如果要求向上取值(即寻找顺序的Set集合中一个大于等于a的第一个元素,日常业务还是用到很多的,不到半斤算半斤(含),超过半斤算一斤类似),可以借用set的floor方法,数值超出元素的最大值后会返回null。
如果是BigDecimal类型,TreeSet集合元素与ceiling参数的小数点位数请务必保持一致。举例如下:

public class SetFloorMethod {
    public static void main(String[] args) {
        Set<BigDecimal> set = new HashSet<>();
        set.add(new BigDecimal(1.2).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(2.3).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(3.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(2.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(0.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        set.add(new BigDecimal(9.4).setScale(2, BigDecimal.ROUND_HALF_UP));
        TreeSet<BigDecimal> sortedSet = new TreeSet<>(Comparator.naturalOrder());
        sortedSet.addAll(set);
        System.out.println(sortedSet);
        BigDecimal value1 = sortedSet.ceiling(new BigDecimal(0.5).setScale(2, BigDecimal.ROUND_HALF_UP));
        System.out.println("根据0.5可以取到元素:" + value1);
        BigDecimal value2 = sortedSet.ceiling(new BigDecimal(2.35).setScale(2, BigDecimal.ROUND_HALF_UP));
        System.out.println("根据2.35可以取到元素:" + value2);
        BigDecimal value3 = sortedSet.ceiling(new BigDecimal(11).setScale(2, BigDecimal.ROUND_HALF_UP));
        System.out.println("根据11可以取到元素:" + value3);
    }
}
--------------------------------------------------------------------------------------------
结果如下:
[0.40, 1.20, 2.30, 2.40, 3.40, 9.40]
根据0.5可以取到元素:1.20
根据2.35可以取到元素:2.40
根据11可以取到元素:null
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值