精华内容
下载资源
问答
  • set scala添加元素 Scala集 (Scala Set) A set in Scala is a collection of unique elements i.e.... Scala中的集合是唯一元素的集合,即,集合中不允许重复元素。 Example: 例: Set(10, 3, 21...

    set scala添加元素

    Scala集 (Scala Set)

    A set in Scala is a collection of unique elements i.e. duplicate elements are not allowed in the Set.

    Scala中的集合是唯一元素的集合,即,集合中不允许重复元素。

    Example:

    例:

        Set(10, 3, 213, 56, 9, 82)
    
    

    访问集合的第一个元素 (Accessing First Element of Set)

    In the Scala programming language, to access the first element of the Set, there are multiple methods defined that can accomplish the task easily.

    在Scala编程语言中,要访问Set的第一个元素,定义了多种方法可以轻松完成任务。

    1)take()方法 (1) take() method)

    The take() method in Scala is used to return the Set of elements up to the specified length from the given Set. So, passing 1 as a parameter to the take() method will return a set with the first element only.

    Scala中take()方法用于从给定Set中返回指定长度的元素Set。 因此,将1作为参数传递给take()方法将仅返回带有第一个元素的集合。

    Program:

    程序:

    object MyClass {
        def main(args: Array[String]) {
            val bike = Set("Pulsar 150" , "Thunderbird 350", "Ninja 300", "Harley Davidson street 750")
            printf("all my bikes are : ")
            println(bike)
            println("My first bike was "+bike.take(1))
        }
    }
    
    

    Output

    输出量

    all my bikes are : Set(Pulsar 150, Thunderbird 350, Ninja 300, Harley Davidson street 750)
    My first bike was Set(Pulsar 150)
    
    

    Here the output is correct i.e. we wanted the first element and we got in too. But in a program, we need to change this set to an element so that it can be used in the code. So, there are other methods too that will do this job for us.

    这里的输出是正确的,即我们想要第一个元素,我们也进入了。 但是在程序中,我们需要将此集合更改为一个元素,以便可以在代码中使用它。 因此,还有其他方法可以为我们完成这项工作。

    2)头法 (2) head method)

    The head method in the Scala is defined to return the first element of the set which call the method.

    Scala中head方法定义为返回集合中调用该方法的第一个元素。

    Syntax:

    句法:

        Set_name.take;
    
    

    The method does not accept any parameter, it returns the first value of the set.

    该方法不接受任何参数,它返回集合的第一个值。

    Program:

    程序:

    object MyClass {
        def main(args: Array[String]) {
            val bike = Set("Pulsar 150" , "Thunderbird 350", "Ninja 300", "Harley Davidson street 750")
            printf("all my bikes are : ")
            println(bike)
            println("My first bike was "+bike.head)
        }
    }
    
    

    Output

    输出量

    all my bikes are : Set(Pulsar 150, Thunderbird 350, Ninja 300, Harley Davidson street 750)
    My first bike was Pulsar 150
    
    

    3)headOption (3) headOption)

    The headOption in Scala is also used to return the first element of the set that calls it.

    Scala中headOption也用于返回集合中调用它的第一个元素。

    Syntax:

    句法:

        set_name.headOption
    
    

    Program:

    程序:

    object MyClass {    
        def main(args: Array[String]) {
            val bike = Set("Pulsar 150" , "Thunderbird 350", "Ninja 300", "Harley Davidson street 750")
            printf("all my bikes are : ")
            println(bike)
            println("My first bike was "+bike.headOption)
        }
    }
    
    

    Output

    输出量

    all my bikes are : Set(Pulsar 150, Thunderbird 350, Ninja 300, Harley Davidson street 750)
    My first bike was Some(Pulsar 150)
    
    
    

    翻译自: https://www.includehelp.com/scala/how-to-get-the-first-element-from-the-set-in-scala.aspx

    set scala添加元素

    展开全文
  • 点击上方蓝色“程序猿DD”,选择“设为星标”回复“资源”获取独家整理学习资料!来源 |公众号「武培轩」Java中Set集合如何实现添加元素保证不重复Set集合一个无序不可以...

    点击上方蓝色“程序猿DD”,选择“设为星标”

    回复“资源”获取独家整理的学习资料!

    来源 | 公众号「武培轩」

    Java中Set集合是如何实现添加元素保证不重复的?

    Set集合是一个无序的不可以重复的集合。今天来看一下为什么不可以重复。

    Set是一个接口,最常用的实现类就是HashSet,今天我们就拿HashSet为例。

    先简单介绍一下HashSet类

    HashSet类实现了Set接口, 其底层其实是包装了一个HashMap去实现的。HashSet采用HashCode算法来存取集合中的元素,因此具有比较好的读取和查找性能。

    先看下HashSet的几个构造方法。

    // 默认构造函数 底层创建一个HashMap
        public HashSet() {
            // 调用HashMap的默认构造函数,创建map
            map = new HashMap<E,Object>();
        }
    
    
        // 带集合的构造函数
        public HashSet(Collection<? extends E> c) {
            // 创建map。
            map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
            // 将集合(c)中的全部元素添加到HashSet中
            addAll(c);
        }
    
    
        // 指定HashSet初始容量和加载因子的构造函数
        public HashSet(int initialCapacity, float loadFactor) {
            map = new HashMap<E,Object>(initialCapacity, loadFactor);
        }
    
    
        // 指定HashSet初始容量的构造函数
        public HashSet(int initialCapacity) {
            map = new HashMap<E,Object>(initialCapacity);
        }
    
    
        HashSet(int initialCapacity, float loadFactor, boolean dummy) {
            map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
        }
    

    再来看HashSet中的声明。

    private transient HashMap<E,Object> map;
     // 用来匹配Map中后面的对象的一个虚拟值
    private static final Object PRESENT = new Object();
    

    接下来就是我们的重点HashSet的add()方法,贴上源码。

        /**
         * 将元素e添加到HashSet中,也就是将元素e作为Key放入HashMap中
         *
         * @param e 要添加到HashSet中的元素
         * @return true 如果不包含该元素
         */
        public boolean add(E e) {
            return map.put(e, PRESENT)==null;
        }
    

    从源码我们可以看出HashSet的add()方法又调用了HashMap中的put()方法,那我们再跳转到HashMap中的put()方法中。

        public V put(K key, V value) {
            // 倒数第二个参数false:表示允许旧值替换
            // 最后一个参数true:表示HashMap不处于创建模式
            return putVal(hash(key), key, value, false, true);
        }
    

    HashMap中的put()方法又调用了putVal()方法来实现功能,再看putVal()的源码。

        final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                       boolean evict) {
            Node<K, V>[] tab;
            Node<K, V> p;
            int n, i;
            //如果哈希表为空,调用resize()创建一个哈希表,并用变量n记录哈希表长度
            if ((tab = table) == null || (n = tab.length) == 0)
                n = (tab = resize()).length;
            /**
             * 如果指定参数hash在表中没有对应的桶,即为没有碰撞
             * Hash函数,(n - 1) & hash 计算key将被放置的槽位
             * (n - 1) & hash 本质上是hash % n,位运算更快
             */
            if ((p = tab[i = (n - 1) & hash]) == null)
                //直接将键值对插入到map中即可
                tab[i] = newNode(hash, key, value, null);
            else {// 桶中已经存在元素
                Node<K, V> e;
                K k;
                // 比较桶中第一个元素(数组中的结点)的hash值相等,key相等
                if (p.hash == hash &&
                        ((k = p.key) == key || (key != null && key.equals(k))))
                    // 将第一个元素赋值给e,用e来记录
                    e = p;
                    // 当前桶中无该键值对,且桶是红黑树结构,按照红黑树结构插入
                else if (p instanceof TreeNode)
                    e = ((TreeNode<K, V>) p).putTreeVal(this, tab, hash, key, value);
                    // 当前桶中无该键值对,且桶是链表结构,按照链表结构插入到尾部
                else {
                    for (int binCount = 0; ; ++binCount) {
                        // 遍历到链表尾部
                        if ((e = p.next) == null) {
                            p.next = newNode(hash, key, value, null);
                            // 检查链表长度是否达到阈值,达到将该槽位节点组织形式转为红黑树
                            if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                                treeifyBin(tab, hash);
                            break;
                        }
                        // 链表节点的<key, value>与put操作<key, value>相同时,不做重复操作,跳出循环
                        if (e.hash == hash &&
                                ((k = e.key) == key || (key != null && key.equals(k))))
                            break;
                        p = e;
                    }
                }
                // 找到或新建一个key和hashCode与插入元素相等的键值对,进行put操作
                if (e != null) { // existing mapping for key
                    // 记录e的value
                    V oldValue = e.value;
                    /**
                     * onlyIfAbsent为false或旧值为null时,允许替换旧值
                     * 否则无需替换
                     */
                    if (!onlyIfAbsent || oldValue == null)
                        e.value = value;
                    // 访问后回调
                    afterNodeAccess(e);
                    // 返回旧值
                    return oldValue;
                }
            }
            // 更新结构化修改信息
            ++modCount;
            // 键值对数目超过阈值时,进行rehash
            if (++size > threshold)
                resize();
            // 插入后回调
            afterNodeInsertion(evict);
            return null;
        }
    

    从源码中,我们可以看出将一个key-value对放入HashMap中时,首先根据key的hashCode()返回值决定该Entry的存储位置,如果两个key的hash值相同,那么它们的存储位置相同。如果这个两个key的equals比较返回true。那么新添加的Entry的value会覆盖原来的Entry的value,key不会覆盖。且HashSet中add()中 map.put(e, PRESENT)==null 为false,HashSet添加元素失败。因此,如果向HashSet中添加一个已经存在的元素,新添加的集合元素不会覆盖原来已有的集合元素。

    往期推荐

    百度开源的 71 个项目,看看你用过几个?

    Spring Boot + Dataway :接口不用写,配配就出来?

    用Java写一个植物大战僵尸简易版!

    GitHub发布重大更新,关系到所有程序员!

    GitHub 热榜:文字识别神器,超轻量级中文 OCR!

    听说你想从事中间件开发?

    扫码登录是如何实现的?

    扫一扫,关注我

    一起学习,一起进步

    展开全文
  • Java的Map集合中没有迭代器,需要将其转换为set集合/*map集合的两种取出方式:1,SetkeySet:将map中所有的键存入到Set集合。因为set具备迭代器。... entrySet:将map集合中的映射关系存入到了set集合中, 而...

    Java的Map集合中没有迭代器,需要将其转换为set集合

    /*map集合的两种取出方式:1,SetkeySet:将map中所有的键存入到Set集合。因为set具备迭代器。 所有可以迭代方式取出所有的键,在根据get方法。获取每一个键对应的值。 Map集合的取出原理:将map集合转成set集合。在通过迭代器取出。2,Set> entrySet:将map集合中的映射关系存入到了set集合中, 而这个关系的数据类型就是:Map.Entry Entry其实就是Map中的一个static内部接口。 为什么要定义在内部呢? 因为只有有了Map集合,有了键值对,才会有键值的映射关系。 关系属于Map集合中的一个内部事物。 而且该事物在直接访问Map集合中的元素。*/import java.util.*;class MapDemo2 { public static void main(String[] args) { Mapmap = new HashMap(); map.put('02','zhangsan2'); map.put('03','zhangsan3'); map.put('01','zhangsan1'); map.put('04','zhangsan4'); //将Map集合中的映射关系取出。存入到Set集合中。 Set> entrySet = map.entrySet(); Iterator> it = entrySet.iterator(); while(it.hasNext()) { Map.Entryme = it.next(); String key = me.getKey(); String value = me.getValue(); System.out.println(key+':'+value); } /* //先获取map集合的所有键的Set集合,keySet(); SetkeySet = map.keySet(); //有了Set集合。就可以获取其迭代器。 Iteratorit = keySet.iterator(); while(it.hasNext()) { String key = it.next(); //有了键可以通过map集合的get方法获取其对应的值。 String value = map.get(key); System.out.println('key:'+key+',value:'+value); } */ }}/*Map.Entry 其实Entry也是一个接口,它是Map接口中的一个内部接口。interface Map{ public static interface Entry { public abstract Object getKey(); public abstract Object getValue(); }}class HashMap implements Map{ class Hahs implements Map.Entry { public Object getKey(){} public Object getValue(){} } }*/

    练习题:

    /*每一个学生都有对应的归属地。学生Student,地址String。学生属性:姓名,年龄。注意:姓名和年龄相同的视为同一个学生。保证学生的唯一性。1,描述学生。2,定义map容器。将学生作为键,地址作为值。存入。3,获取map集合中的元素。*/import java.util.*;class Student implements Comparable{ private String name; private int age; Student(String name,int age) { this.name = name; this.age = age; } //为了确保使用TreeSet集合存储元素,使得Student类实现Comparable接口和实现compareTo方法 public int compareTo(Student s) { int num = new Integer(this.age).compareTo(new Integer(s.age)); if(num==0) return this.name.compareTo(s.name); return num; }//为了确保使用HashSet集合存储元素,实现hashCode和equals方法 public int hashCode(){return name.hashCode()+age*34;}public boolean equals(Object obj){if(!(obj instanceof Student))throw new ClassCastException('类型不匹配');Student s = (Student)obj;return this.name.equals(s.name) && this.age==s.age;}public String getName(){return name;}public int getAge(){return age;}public String toString(){return name+':'+age;}}class MapTest{public static void main(String[] args) {HashMaphm = new HashMap();hm.put(new Student('lisi1',21),'beijing');hm.put(new Student('lisi1',21),'tianjin');hm.put(new Student('lisi2',22),'shanghai');hm.put(new Student('lisi3',23),'nanjing');hm.put(new Student('lisi4',24),'wuhan');//第一种取出方式 keySetSetkeySet = hm.keySet();Iteratorit = keySet.iterator();while(it.hasNext()){Student stu = it.next();String addr = hm.get(stu);System.out.println(stu+'..'+addr);}//第二种取出方式 entrySetSet> entrySet = hm.entrySet();Iterator> iter = entrySet.iterator();while(iter.hasNext()){Map.Entryme = iter.next();Student stu = me.getKey();String addr = me.getValue();System.out.println(stu+'.........'+addr);}}}

    练习2

    展开全文
  • 前几篇文章中,咱们聊到 List、Map 接口相关的实现类,今天咱们来聊聊集合中的 Set 接口!01、摘要关于 Set 接口,在实际开发中,其实很少用到,但是如果你出去面试,它可能依然是一个绕不开的话题。言归正传,废话...

    前几篇文章中,咱们聊到 List、Map 接口相关的实现类,今天咱们来聊聊集合中的 Set 接口!

    01、摘要

    关于 Set 接口,在实际开发中,其实很少用到,但是如果你出去面试,它可能依然是一个绕不开的话题。

    言归正传,废话咱们也不多说了,相信使用过 Set 集合类的朋友都知道,Set集合的特点主要有:元素不重复、存储无序的特点。

    啥意思呢?你可以理解为,向一个瓶子里面扔东西,这些东西没有记号是第几个放进去的,但是有一点就是这个瓶子里面不会有重样的东西。

    细细思考,你会发现, Set 集合的这些特性正处于 List 集合和 Map 集合之间,为什么这么说呢?之前的集合文章中,咱们了解到,List 集合的特点就是存取有序,本质是一个有序数组,每个元素依次按照顺序存储;Map 集合主要用于存放键值对,虽然底层也是用数组存放,但是元素在数组中的下标是通过哈希算法计算出来的,数组下标无序

    而 Set 集合,在元素存储方面,注重独立无二的特性,如果某个元素在集合中已经存在,不会存储重复的元素,同时,集合存储的是元素,不像 Map 集合那样存储的是键值对。

    具体的分析,咱们慢慢道来,打开 Set 集合,主要实现类有 HashSet、LinkedHashSet 、TreeSet 、EnumSet( RegularEnumSet、JumboEnumSet )等等,总结 Set 接口实现类,图如下:

    32d54f0b99d1e22390f1a5254d0863d4.png

    由图中的继承关系,可以知道,Set 接口主要实现类有 AbstractSet、HashSet、LinkedHashSet 、TreeSet 、EnumSet( RegularEnumSet、JumboEnumSet ),其中 AbstractSet、EnumSet 属于抽象类,EnumSet 是在 jdk1.5 中新增的,不同的是 EnumSet 集合元素必须是枚举类型。

    • HashSet 是一个输入输出无序的集合,集合中的元素基于 HashMap 的 key 实现,元素不可重复;
    • LinkedHashSet 是一个输入输出有序的集合,集合中的元素基于 LinkedHashMap 的 key 实现,元素也不可重复;
    • TreeSet 是一个排序的集合,集合中的元素基于 TreeMap 的 key 实现,同样元素不可重复;
    • EnumSet 是一个与枚举类型一起使用的专用 Set 集合,其中 RegularEnumSet 和 JumboEnumSet 不能单独实例化,只能由 EnumSet 来生成,同样元素不可重复;

    下面咱们来对各个主要实现类进行一一分析!

    02、HashSet

    HashSet 是一个输入输出无序的集合,底层基于 HashMap 来实现,HashSet 利用 HashMap 中的key元素来存放元素,这一点我们可以从源码上看出来,阅读源码如下:

    public class HashSet    extends AbstractSet    implements Set, Cloneable, java.io.Serializable{        // HashMap 变量    private transient HashMap map;        /**HashSet 初始化*/    public HashSet() {        //默认实例化一个 HashMap        map = new HashMap<>();    }}

    2.1、add方法

    打开HashSet的add()方法,源码如下:

    public boolean add(E e) {    //向 HashMap 中添加元素    return map.put(e, PRESENT)==null;}

    其中变量PRESENT,是一个非空对象,源码部分如下:

    private static final Object PRESENT = new Object();

    可以分析出,当进行add()的时候,等价于

    HashMap map = new HashMap<>();map.put(e, new Object());//e 表示要添加的元素

    在之前的集合文章中,咱们了解到 HashMap 在添加元素的时候 ,通过equals()和hashCode()方法来判断传入的key是否相同,如果相同,那么 HashMap 认为添加的是同一个元素,反之,则不是。

    从源码分析上可以看出,HashSet 正是使用了 HashMap 的这一特性,实现存储元素下标无序、元素不会重复的特点。

    2.2、remove方法

    HashSet 的删除方法,同样如此,也是基于 HashMap 的底层实现,源码如下:

    public boolean remove(Object o) {    //调用HashMap 的remove方法,移除元素    return map.remove(o)==PRESENT;}

    2.3、查询方法

    HashSet 没有像 List、Map 那样提供 get 方法,而是使用迭代器或者 for 循环来遍历元素,方法如下:

    public static void main(String[] args) {    Set hashSet = new HashSet();    System.out.println("HashSet初始容量大小:"+hashSet.size());    hashSet.add("1");    hashSet.add("2");    hashSet.add("3");    hashSet.add("3");    hashSet.add("2");    hashSet.add(null);    //相同元素会自动覆盖    System.out.println("HashSet容量大小:"+hashSet.size());    //迭代器遍历    Iterator iterator = hashSet.iterator();    while (iterator.hasNext()){        String str = iterator.next();        System.out.print(str + ",");    }    System.out.println("===========");    //增强for循环    for (String str : hashSet) {        System.out.print(str + ",");    }}

    输出结果:

    HashSet初始容量大小:0HashSet容量大小:4null,1,2,3,===========null,1,2,3,

    需要注意的是,HashSet 允许添加为null的元素。

    03、LinkedHashSet

    LinkedHashSet 是一个输入输出有序的集合,继承自 HashSet,但是底层基于 LinkedHashMap 来实现。

    如果你之前了解过 LinkedHashMap,那么你一定知道,它也继承自 HashMap,唯一有区别的是,LinkedHashMap 底层数据结构基于循环链表实现,并且数组指定了头部和尾部,虽然数组的下标存储无序,但是却可以通过数组的头部和尾部,加上循环链表,依次可以查询到元素存储的过程,从而做到输入输出有序的特点

    如果还不了解 LinkedHashMap 的实现过程,可以参阅集合系列中关于 LinkedHashMap 的实现过程文章。

    阅读 LinkedHashSet 的源码,类定义如下:

    public class LinkedHashSet    extends HashSet    implements Set, Cloneable, java.io.Serializable {    public LinkedHashSet() {        //调用 HashSet 的方法        super(16, .75f, true);    }}

    查询源码,super调用的方法,源码如下:

    HashSet(int initialCapacity, float loadFactor, boolean dummy) {    //初始化一个 LinkedHashMap    map = new LinkedHashMap<>(initialCapacity, loadFactor);}

    3.1、add方法

    LinkedHashSet没有重写add方法,而是直接调用HashSet的add()方法,因为map的实现类是LinkedHashMap,所以此处是向LinkedHashMap中添加元素,当进行add()的时候,等价于

    HashMap map = new LinkedHashMap<>();map.put(e, new Object());//e 表示要添加的元素

    3.2、remove方法

    LinkedHashSet也没有重写remove方法,而是直接调用HashSet的删除方法,因为LinkedHashMap没有重写remove方法,所以调用的也是HashMap的remove方法,源码如下:

    public boolean remove(Object o) {    //调用HashMap 的remove方法,移除元素    return map.remove(o)==PRESENT;}

    3.3、查询方法

    同样的,LinkedHashSet 没有提供 get 方法,使用迭代器或者 for 循环来遍历元素,方法如下:

    public static void main(String[] args) {    Set linkedHashSet = new LinkedHashSet();    System.out.println("linkedHashSet初始容量大小:"+linkedHashSet.size());    linkedHashSet.add("1");    linkedHashSet.add("2");    linkedHashSet.add("3");    linkedHashSet.add("3");    linkedHashSet.add("2");    linkedHashSet.add(null);    linkedHashSet.add(null);    System.out.println("linkedHashSet容量大小:"+linkedHashSet.size());    //迭代器遍历    Iterator iterator = linkedHashSet.iterator();    while (iterator.hasNext()){        String str = iterator.next();        System.out.print(str + ",");    }    System.out.println("===========");    //增强for循环    for (String str : linkedHashSet) {        System.out.print(str + ",");    }}

    输出结果:

    linkedHashSet初始容量大小:0linkedHashSet容量大小:41,2,3,null,===========1,2,3,null,

    可见,LinkedHashSet 与 HashSet 相比,LinkedHashSet 输入输出有序。

    04、TreeSet

    TreeSet 是一个排序的集合,实现了NavigableSet、SortedSet、Set接口,底层基于 TreeMap 来实现。TreeSet 利用 TreeMap 中的key元素来存放元素,这一点我们也可以从源码上看出来,阅读源码,类定义如下:

    public class TreeSet extends AbstractSetimplements NavigableSet, Cloneable, java.io.Serializable {        //TreeSet 使用NavigableMap接口作为变量    private transient NavigableMap m;        /**对象初始化*/    public TreeSet() {        //默认实例化一个 TreeMap 对象        this(new TreeMap());    }        //对象初始化调用的方法    TreeSet(NavigableMap m) {        this.m = m;    }}

    new TreeSet<>() 对象实例化的时候,表达的意思,可以简化为如下:

    NavigableMap m = new TreeMap();

    因为TreeMap实现了NavigableMap接口,所以没啥问题。

    public class TreeMap    extends AbstractMap    implements NavigableMap, Cloneable, java.io.Serializable{    ......}

    4.1、add方法

    打开TreeSet的add()方法,源码如下:

    public boolean add(E e) {    //向 TreeMap 中添加元素    return m.put(e, PRESENT)==null;}

    其中变量PRESENT,也是是一个非空对象,源码部分如下:

    private static final Object PRESENT = new Object();

    可以分析出,当进行add()的时候,等价于

    TreeMap map = new TreeMap<>();map.put(e, new Object());//e 表示要添加的元素

    TreeMap 类主要功能在于,给添加的集合元素,按照一个的规则进行了排序,默认以自然顺序进行排序,当然也可以自定义排序,比如测试方法如下:

    public static void main(String[] args) {    Map initMap = new TreeMap();    initMap.put("4", "d");    initMap.put("3", "c");    initMap.put("1", "a");    initMap.put("2", "b");    //默认自然排序,key为升序    System.out.println("默认 排序结果:" + initMap.toString());    //自定义排序,在TreeMap初始化阶段传入Comparator 内部对象    Map comparatorMap = new TreeMap(new Comparator() {        @Override        public int compare(String o1, String o2){            //根据key比较大小,采用倒叙,以大到小排序            return o2.compareTo(o1);        }    });    comparatorMap.put("4", "d");    comparatorMap.put("3", "c");    comparatorMap.put("1", "a");    comparatorMap.put("2", "b");    System.out.println("自定义 排序结果:" + comparatorMap.toString());}

    输出结果:

    默认 排序结果:{1=a, 2=b, 3=c, 4=d}自定义 排序结果:{4=d, 3=c, 2=b, 1=a}

    相信使用过TreeMap的朋友,一定知道TreeMap会自动将key按照一定规则进行排序,TreeSet正是使用了TreeMap这种特性,来实现添加的元素集合,在输出的时候,其结果是已经排序好的。

    如果您没看过源码TreeMap的实现过程,可以参阅集合系列文章中TreeMap的实现过程介绍,或者阅读 jdk 源码。

    4.2、remove方法

    TreeSet 的删除方法,同样如此,也是基于 TreeMap 的底层实现,源码如下:

    public boolean remove(Object o) {        //调用TreeMap 的remove方法,移除元素        return m.remove(o)==PRESENT;}

    4.3、查询方法

    TreeSet 没有重写 get 方法,而是使用迭代器或者 for 循环来遍历元素,方法如下:

    public static void main(String[] args) {    Set treeSet = new TreeSet<>();    System.out.println("treeSet初始容量大小:"+treeSet.size());    treeSet.add("1");    treeSet.add("4");    treeSet.add("3");    treeSet.add("8");    treeSet.add("5");    System.out.println("treeSet容量大小:"+treeSet.size());    //迭代器遍历    Iterator iterator = treeSet.iterator();    while (iterator.hasNext()){        String str = iterator.next();        System.out.print(str + ",");    }    System.out.println("===========");    //增强for循环    for (String str : treeSet) {        System.out.print(str + ",");    }}

    输出结果:

    treeSet初始容量大小:0treeSet容量大小:51,3,4,5,8,===========1,3,4,5,8,

    4.4、自定义排序

    使用自定义排序,有 2 种方法,第一种在需要添加的元素类,实现Comparable 接口,重写compareTo方法来实现对元素进行比较,实现自定义排序。

    方法一
    /**  * 创建实体类Person实现Comparable接口  */public class Person implements Comparable{    private int age;    private String name;    public Person(String name, int age){        this.name = name;        this.age = age;    }    @Override    public int compareTo(Person o){        //重写 compareTo 方法,自定义排序算法        return this.age-o.age;    }    @Override    public String toString(){        return name+":"+age;    }}

    创建一个Person实体类,实现Comparable接口,重写compareTo方法,通过变量age实现自定义排序 测试方法如下:

    public static void main(String[] args) {    Set treeSet = new TreeSet<>();    System.out.println("treeSet初始容量大小:"+treeSet.size());    treeSet.add(new Person("李一",18));    treeSet.add(new Person("李二",17));    treeSet.add(new Person("李三",19));    treeSet.add(new Person("李四",21));    treeSet.add(new Person("李五",20));    System.out.println("treeSet容量大小:"+treeSet.size());    System.out.println("按照年龄从小到大,自定义排序结果:");    //迭代器遍历    Iterator iterator = treeSet.iterator();    while (iterator.hasNext()){        Person person = iterator.next();        System.out.print(person.toString() + ",");    }}

    输出结果:

    treeSet初始容量大小:0treeSet容量大小:5按照年龄从小到大,自定义排序结果:李二:17,李一:18,李三:19,李五:20,李四:21,
    方法二

    第二种方法是在TreeSet初始化阶段,Person不用实现Comparable接口,将Comparator 接口以内部类的形式作为参数,初始化进去,方法如下:

    public static void main(String[] args) {    //自定义排序    Set treeSet = new TreeSet<>(new Comparator(){        @Override        public int compare(Person o1, Person o2) {            if(o1 == null || o2 == null){                //不用比较                return 0;            }            //从小到大进行排序            return o1.getAge() - o2.getAge();        }    });    System.out.println("treeSet初始容量大小:"+treeSet.size());    treeSet.add(new Person("李一",18));    treeSet.add(new Person("李二",17));    treeSet.add(new Person("李三",19));    treeSet.add(new Person("李四",21));    treeSet.add(new Person("李五",20));    System.out.println("treeSet容量大小:"+treeSet.size());    System.out.println("按照年龄从小到大,自定义排序结果:");    //迭代器遍历    Iterator iterator = treeSet.iterator();    while (iterator.hasNext()){        Person person = iterator.next();        System.out.print(person.toString() + ",");    }}

    输出结果:

    treeSet初始容量大小:0treeSet容量大小:5按照年龄从小到大,自定义排序结果:李二:17,李一:18,李三:19,李五:20,李四:21,

    需要注意的是,TreeSet不能添加为空的元素,否则会报空指针错误!

    05、EnumSet

    EnumSet 是一个与枚举类型一起使用的专用 Set 集合,继承自AbstractSet抽象类。与 HashSet、LinkedHashSet 、TreeSet 不同的是,EnumSet 元素必须是Enum的类型,并且所有元素都必须来自同一个枚举类型,EnumSet 定义源码如下:

    public abstract class EnumSet> extends AbstractSet    implements Cloneable, java.io.Serializable {    ......}

    EnumSet是一个虚类,不能直接通过实例化来获取对象,只能通过它提供的静态方法来返回EnumSet实现类的实例。

    EnumSet的实现类有两个,分别是RegularEnumSet、JumboEnumSet两个类,两个实现类都继承自EnumSet。

    EnumSet会根据枚举类型中元素的个数,来决定是返回哪一个实现类,当 EnumSet元素中的元素个数小于或者等于64,就会返回RegularEnumSet实例;当EnumSet元素个数大于64,就会返回JumboEnumSet实例。

    这一点,我们可以从源码中看出,源码如下:

    public static > EnumSet noneOf(Class elementType) {    Enum>[] universe = getUniverse(elementType);    if (universe == null)        throw new ClassCastException(elementType + " not an enum");    //当元素个数小于或者等于 64 的时候,返回 RegularEnumSet    if (universe.length <= 64)        return new RegularEnumSet<>(elementType, universe);    else        //大于64,返回 JumboEnumSet        return new JumboEnumSet<>(elementType, universe);}

    noneOf是EnumSet中一个静态方法,用于判断是返回哪一个实现类。

    我们来看看当元素个数小于等于64的时候,使用RegularEnumSet的类,源码如下:

    class RegularEnumSet> extends EnumSet {    /**元素为long型*/    private long elements = 0L;    /**添加元素*/    public boolean add(E e) {        typeCheck(e);        long oldElements = elements;        //二进制运算,获取元素        elements |= (1L << ((Enum>)e).ordinal());        return elements != oldElements;    }}

    RegularEnumSet 通过二进制运算得到结果,直接使用long来存放元素。

    我们再来看看当元素个数大于64的时候,使用JumboEnumSet的类,源码如下:

    class JumboEnumSet> extends EnumSet {    /**元素为long型*/    private long elements = 0L;    /**添加元素*/    public boolean add(E e) {        typeCheck(e);        int eOrdinal = e.ordinal();        int eWordNum = eOrdinal >>> 6;        long oldElements = elements[eWordNum];        //二进制运算        elements[eWordNum] |= (1L << eOrdinal);        //使用数组来操作元素        boolean result = (elements[eWordNum] != oldElements);        if (result)            size++;        return result;    }}

    JumboEnumSet 也是通过二进制运算得到结果,使用long来存放元素,但是它是使用数组来存放元素。

    二者相比,RegularEnumSet 效率比 JumboEnumSet 高些,因为操作步骤少,大多数情况下返回的是 RegularEnumSet,只有当枚举元素个数超过 64 的时候,会使用 JumboEnumSet。

    5.1、添加元素

    新建一个EnumEntity的枚举类型,定义2个参数。

    public enum EnumEntity {    WOMAN,MAN;}

    创建一个空的 EnumSet!

    //创建一个 EnumSet,内容为空EnumSet noneSet = EnumSet.noneOf(EnumEntity.class);System.out.println(noneSet);

    输出结果:

    []

    创建一个 EnumSet,并将枚举类型的元素全部添加进去!

    //创建一个 EnumSet,将EnumEntity 元素内容添加到EnumSet中EnumSet allSet = EnumSet.allOf(EnumEntity.class);System.out.println(allSet);

    输出结果:

    [WOMAN, MAN]

    创建一个 EnumSet,添加指定的枚举元素!

    //创建一个 EnumSet,添加 WOMAN 到 EnumSet 中EnumSet customSet = EnumSet.of(EnumEntity.WOMAN);System.out.println(customSet);

    5.2、查询元素

    EnumSet与HashSet、LinkedHashSet、TreeSet一样,通过迭代器或者 for 循环来遍历元素,方法如下:

    EnumSet allSet = EnumSet.allOf(EnumEntity.class);for (EnumEntity enumEntity : allSet) {    System.out.print(enumEntity + ",");}

    输出结果:

    WOMAN,MAN,

    06、总结

    d0075e641e85ba4b5e6c14bd5441e76c.png
    • HashSet 是一个输入输出无序的 Set 集合,元素不重复,底层基于 HashMap 的 key 来实现,元素可以为空,如果添加的元素为对象,对象需要重写 equals() 和 hashCode() 方法来约束是否为相同的元素。
    • LinkedHashSet 是一个输入输出有序的 Set 集合,继承自 HashSet,元素不重复,底层基于 LinkedHashMap 的 key来实现,元素也可以为空,LinkedHashMap 使用循环链表结构来保证输入输出有序。
    • TreeSet 是一个排序的 Set 集合,元素不可重复,底层基于 TreeMap 的 key来实现,元素不可以为空,默认按照自然排序来存放元素,也可以使用 Comparable 和 Comparator 接口来比较大小,实现自定义排序。
    • EnumSet 是一个与枚举类型搭配使用的专用 Set 集合,在 jdk1.5 中加入。EnumSet 是一个虚类,有2个实现类 RegularEnumSet、JumboEnumSet,不能显式的实例化改类,EnumSet 会动态决定使用哪一个实现类,当元素个数小于等于64的时候,使用 RegularEnumSet;大于 64的时候,使用JumboEnumSet类,EnumSet 其内部使用位向量实现,拥有极高的时间和空间性能,如果元素是枚举类型,推荐使用 EnumSet。

    07、参考

    1、JDK1.7&JDK1.8 源码

    2、程序园 - java集合-EnumMap与EnumSet

    展开全文
  • Java中如何取出Map集合中的元素

    千次阅读 2014-11-20 15:31:07
    /* map集合的两种取出方式: 1,Set keySet:将map中所有的键存入到Set集合。因为set具备迭代器。...2,Set> entrySet:将map集合中的映射关系存入到了set集合中, 而这关系的数据类型就是:Map.
  • Map集合如何取出所有元素

    千次阅读 2018-03-29 11:20:47
    1:map.put(8,"zhaoliu"); map.put(2,"... //原理,通过keySet方法获取map所有键所在的Set集合,在通过Set迭代器获取到每一个键, //在对每一个键通过map集合get方法获取其对...
  • 文章目录1、Set集合定义2、 set集合创建3、如何创建一个set集合4、set集合添加元素4、set集合元素的移除5、获取set集合元素个数6、清空集合 通过clear()方法7、判断元素是否在set集合中8、计算两个集合...
  • 摘要缓存中间件Redis拥有许多丰富、重要且有趣的数据结构,集合Set便是其中的一个佼佼者,其核心特性跟JavaSE集合体系中的Set几乎一毛一样,即"无序"且"唯一",当我们向集合Set伸手要一个元素时,其底层会随机地给...
  • Java 集合20 Map 获取

    2018-09-13 14:59:15
    获取集合中的元素。之前只能使用,get(键) 返回值。但是如果我们要获取集合中的所有元素,键就要不断的变化 如何取得所有的键? 在返回所有键的方法中,因为时所有的键,所以返回值的类型应该是一个集合,这个集合...
  • 如何遍历map集合

    千次阅读 2018-11-26 20:49:59
    values() : 是获取集合中的所有的值----没有键,没有对应关系。 KeySet() : 将Map中所有的键存入到set集合中。因为set具备迭代器。所有可以迭代方式取出所有的键,再根据get方法。获取一个键对应的值...
  • 集合(set) 类型也是用来...并且集合中的元素是无序的,不能通过索引下标获取元素。一个集合最多可以存储2^32 -1 个元素。Redis除了支持集合的增删改查,同时还支持多个集合取交集,并集,差集。  基本命令:  ...
  • 1.Set简述 Set(接口):元素无序,不可以重复(内存地址不可重复),称为集; 常见是实现类HashSet,即哈希集;...取Set中元素时,因为Set是无序,所以没有index,此时需要使用迭代器去获取 So如何得到迭
  • 集合是极大简化我们工作效率的一种类型,我们可以通过它存储同类型的多条数据(Array);可以存储同类型且唯一的多条...在日常开发,我们会经常获取数组的元素,那么我们应该如何获取集合的第一个元素呢? 可以通...
  • set的基础上,增加了一个值,set k1 v1 zset k1 score v1 排序如何实现 移除rem中的元素 获取指定区间的成员数量 其余的一些API,如果有需要,可以去查看官方的文档! 案列思路: set 排序 存储班级成绩表...
  • 知识点回顾 什么是迭代器:一个遍历集合的对象。... E next():先将指针下移指向下一个元素,并返回当前指针指向位置元素。 迭代器使用注意事项: hasNext和next方法必须成对出现 迭代器过程不...
  • 遍历Java中的Map

    2020-11-22 11:44:57
    今早遇到了轮询map中的元素,加入到list中的需求 相关材料: ... 如何遍历Map 一、利用Map内部的entrySet,Set集合进行foreach Map中的每个节点都是...利用这个方法,我们能获取一个Set集合,该集合是Collection的子类.
  • Stream不会修改数据源,而是会产生一个修改后的Stream对象,进而链式调用 Stream的执行具有延迟特性 如何创建Stream对象: 1.从数组中获取Stream对象 //方式1:Arrays中的静态stream方法 Integer[] arr= {1...
  • (分别还有利用哈希表实现unordered版本)其中,字典(映射)键(Keys)可视作组成一个相应类型的集合。 对于集合或字典读取,经典操作有两个:判断目标元素是否在集合当中、根据目标键获取相应值。 这篇...
  • Java---集合(2)

    2019-08-11 14:31:10
    1.Set集合 1.1 概述和特点 Set集合的特点 元素存取无序 没有索引、只能通过迭代器... 如何获取哈希值 Object类中的public int hashCode():返回对象的哈希码值 哈希值的特点 同一个对象多次调用hashCode()方...
  • python set() 和 dict()

    2020-09-19 13:21:56
    set()创建是集合,集合中是没有重复的元素的,数据结构和list和tuple一样,通过.add()和.remove()进行增加和删除元素(注意区别dict哦),当 add重复元素的时候,会自动忽略,不会报错,但删除不存在的元素会报错;...
  • 9.2.2 获取字符串中的一部分 222 9.2.3 判断两字符串是否相等 223 9.2.4 判断字符串的开头和结尾 225 9.2.5 分割字符串 225 9.2.6 在字符串中查找子字符串或字符 226 9.2.7 替换字符串中的内容 226 9.2.8 ...
  • # 匹配第一个参数路径所有符合条件文件,并将其以list形式返回。 input_paths = glob.glob(os.path.join(input_dir, "*.jpg")) # 图像解码器 decode = tf.image.decode_jpeg if len(input_...
  • 9.2.2 获取字符串中的一部分 222 9.2.3 判断两字符串是否相等 223 9.2.4 判断字符串的开头和结尾 225 9.2.5 分割字符串 225 9.2.6 在字符串中查找子字符串或字符 226 9.2.7 替换字符串中的内容 226 9.2.8 ...
  • 9.2.2 获取字符串中的一部分 222 9.2.3 判断两字符串是否相等 223 9.2.4 判断字符串的开头和结尾 225 9.2.5 分割字符串 225 9.2.6 在字符串中查找子字符串或字符 226 9.2.7 替换字符串中的内容 226 9.2.8 ...
  • list Python内置数据类型是列表:list。其是种有序的集合,可以随时删除添加其中元素。...list_name[n] #访问第n+1个元素,索引从0开始,和C数组一样,访问过界会报错,n也可以为负整数,list_name...
  • 在map虽然不能直接实例化迭代器,但map集合提供了keySet()方法和value()方法,可以通过先将键值输出到一个集合,可以是list集合或者set集合。 2.通过键集合就可以直接实例化迭代器。 3.在进行迭代操...
  • 先看看官方文档是如何解释两者之间功能差异: attr() Get the value of an attribute for the first element in the set of matched elements or set one or ... 获取匹配元素集合中一个元素的attribu...
  • VBSCRIPT中文手册

    热门讨论 2010-11-12 10:13:06
    For Each...Next 语句 对于数组或集合中的一个元素,重复一组语句。 FormatCurrency 函数 返回的表达式为货币值格式,其货币符号采用系统控制面板中定义的。 FormatDateTime 函数 返回格式化为日期或时间的...
  • public class SnakeNode {//定义蛇身集合中的各个元素点 private int x; private int y; private Color color; public SnakeNode() { super(); // TODO Auto-generated constructor stub } public ...

空空如也

空空如也

1 2 3 4 5
收藏数 81
精华内容 32
关键字:

如何获取set集合中的一个元素