拥抱Guava之集合操作

深入Guava集合操作

在Java开发中,Google Guava库是处理集合的强大工具。起源于Google内部需求,Guava以简洁性、性能优化为理念,提供高效不可变集合和实用工具类。本文深入剖析Guava的核心功能,为开发者呈现集合操作的全新视角,无论经验水平,都能获得实用技巧和深刻见解。

一、不可变集合

1、为什么使用不可变集合

不可变对象有很多优点,包括:

  • 当对象被不可信的库调用时,不可变形式是安全的;
  • 不可变对象被多个线程调用时,不存在竞态条件问题
  • 可变集合不需要考虑变化,因此可以节省时间和空间。所有不可变的集合都比它们的可变形式有更好的内存利用率(分析和测试细节);
  • 不可变对象因为有固定不变,可以作为常量来安全使用。
2、创建不可变集合的方式:
  • copyOf方法,如ImmutableSet.copyOf(set);
  • of方法,如ImmutableSet.of(“a”, “b”, “c”)或 ImmutableMap.of(“a”, 1, “b”, 2);
  • Builder工具,如:
private static final ImmutableSet<String> SET = ImmutableSet.<String>builder().add("a","b").addAll(Lists.newArrayList("c","d")).build();

此外,对有序不可变集合来说,排序是在构造集合的时候完成的,如: ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");

会在构造时就把元素排序为a, b, c, d。

3、asList视图

所有不可变集合都有一个asList()方法提供ImmutableList视图,来帮助你用列表形式方便地读取集合元素。例如,你可以使用sortedSet.asList().get(k)从ImmutableSortedSet中读取第k个最小元素。

asList()返回的ImmutableList通常是——并不总是——开销稳定的视图实现,而不是简单地把元素拷贝进List。也就是说,asList返回的列表视图通常比一般的列表平均性能更好,比如,在底层集合支持的情况下,它总是使用高效的contains方法。

二、关联可变集合和不可变集合

可变集合接口属于JDK还是Guava不可变版本
CollectionJDKImmutableCollection
ListJDKImmutableList
SetJDKImmutableSet
SortedSet/NavigableSetJDKImmutableSortedSet
MapJDKImmutableMap
SortedMapJDKImmutableSortedMap
MultisetGuavaImmutableMultiset
SortedMultisetGuavaImmutableSortedMultiset
MultimapGuavaImmutableMultimap
ListMultimapGuavaImmutableListMultimap
SetMultimapGuavaImmutableSetMultimap
BiMapGuavaImmutableBiMap
ClassToInstanceMapGuavaImmutableClassToInstanceMap
TableGuavaImmutableTable

三、新集合类型

1、Multiset

Multiset可以多次添加相等元素,集合[set]概念的延伸,它的元素可以重复出现…与集合[set]相同而与元组[tuple]相反的是,Multiset元素的顺序是无关紧要的:Multiset {a, a, b}和{a, b, a}是相等的

可以用两种方式看待Multiset:

  • 没有元素顺序限制的ArrayList
  • Map<E, Integer>,键为元素,值为计数
(1)、常见方法
方法描述
int count(E)给定元素在Multiset中的计数
Set<E> elementSet()Multiset中不重复元素的集合,类型为Set<E>
Set<Multiset.Entry<E>> entrySet()和Map的entrySet类似,返回Set<Multiset.Entry<E>>,其中包含的Entry支持getElement()和getCount()方法
int add(E, int)增加给定元素在Multiset中的计数
boolean add(E element)增加一个指定的元素到multiset
boolean contains(E element)判断此多集中是否包含指定的元素
boolean containsAll(Collection<?> elements)判断此多集至少包含一个出现指定集合的所有元素
remove(E, int)减少给定元素在Multiset中的计数,删除指定元素
removeAll(Collection<?> c)删除包含在指定集合中的元素
boolean retainAll(Collection<?> e)保持包含指定集合中的元素
int setCount(E, int)设置给定元素在Multiset中的计数,不可以为负数,添加/删除指定元素,使其达到所期望的元素个数
int size()返回集合元素的总个数(包括重复的元素)
Iterator iterator()返回一个迭代器,包含Multiset的所有元素(包括重复的元素)
(2)、示例
    /*** MultiSet*/@Testpublic void multiSetTest(){Multiset<String> multiset = HashMultiset.create();List<String> list = Lists.newArrayList("a","b","c","d","a","c","d","a","d","a");multiset.addAll(list);System.out.println("a的个数:"+multiset.count("a"));System.out.println("multiset的个数:"+multiset.size());Set<String> set = multiset.elementSet();System.out.println("不重复元素:"+ Joiner.on(",").join(set));Iterator<String> iterator = multiset.iterator();System.out.println("multiset元素:"+Joiner.on(",").join(iterator));Set<Multiset.Entry<String>> entrySet =  multiset.entrySet();Map<String,Integer> setMap = Maps.newHashMap();entrySet.forEach(e -> {setMap.put(e.getElement(),e.getCount());});System.out.println("元素详情:"+Joiner.on(";").withKeyValueSeparator("=").join(setMap));multiset.remove("a",2);System.out.println("删除a后,a的个数:"+multiset.count("a"));System.out.println("是否包含List:"+multiset.containsAll(Lists.newArrayList("a","c")));System.out.println("是否包含List:"+multiset.containsAll(Lists.newArrayList("a","c","e")));}
(3)、SortedMultiset

SortedMultiset是Multiset 接口的变种,它支持高效地获取指定范围的子集

2、MultiMap

Multimap可以很容易地把一个键映射到多个值。换句话说,Multimap是把键映射到任意多个值的一般方式。 可以用两种方式思考Multimap的概念:”键-单个值映射”的集合:
a -> 1 a -> 2 a ->4 b -> 3 c -> 5
或者”键-值集合映射”的映射:
a -> [1, 2, 4] b -> 3 c -> 5
一般来说,Multimap接口应该用第一种方式看待,但asMap()视图返回Map<K, Collection>,让你可以按另一种方式看待Multimap。重要的是,不会有任何键映射到空集合:一个键要么至少到一个值,要么根本就不在Multimap中。 很少会直接使用Multimap接口,更多时候你会用ListMultimap或SetMultimap接口,它们分别把键映射到List或Set。

(1)、常用方法
方法描述等价于
boolean put(K, V)添加键到单个值的映射multimap.get(key).add(value)
boolean putAll(K, Iterable<V>)依次添加键到多个值的映射Iterables.addAll(multimap.get(key), values)
remove(K, V)移除键到值的映射;如果有这样的键值并成功移除,返回true。multimap.get(key).remove(value)
removeAll(K)清除键对应的所有值,返回的集合包含所有之前映射到K的值,但修改这个集合就不会影响Multimap了。multimap.get(key).clear()
replaceValues(K, Iterable<V>)清除键对应的所有值,并重新把key关联到Iterable中的每个元素。返回的集合包含所有之前映射到K的值。multimap.get(key).clear(); Iterables.addAll(multimap.get(key), values)
Map<K,Collection<V>> asMap()获取MultiMap的视图,键值K,以及K对应的集合
void clear()清除所有的键值对
boolean containsEntry(Object key,Object value)判断是否包含key-value对应的键值对
boolean containsKey(Object key)判断是否包含键值key
boolean containsValue(Object value)判断是否包含值value
Collection<Map.Entry<K,V>> entries()MultiMap为Map<Entry>情况下,返回所有的键值对集合
Collection<V> get(K k)返回键k对应的所有集合
boolean isEmpty()判断MultiMap是否是空,即不包含键值对
MultiSet<K> keys()返回所有的键值K,包含重复
Set<K> keySet()返回所有的键值K,不重复
int size()返回键值对的数量
Collection<V> values返回所有的value
(2)、示例
    /*** MultiMap*/@Testpublic void multiMapTest(){Multimap<String,String> multimap = HashMultimap.create();multimap.putAll("lower",Lists.newArrayList("a","b","c","d"));multimap.putAll("upper",Lists.newArrayList("A","B","C","D"));Map<String, Collection<String>> asMap = multimap.asMap();System.out.println("asMap视图:"+Joiner.on(";").withKeyValueSeparator("=").join(asMap));Multiset<String> multisetKey = multimap.keys();System.out.println("所有的key:"+Joiner.on(",").join(multisetKey.iterator()));Set<String> keySet = multimap.keySet();System.out.println("不重复的key:"+Joiner.on(",").join(keySet));System.out.println("lower:"+Joiner.on(",").join(multimap.get("lower")));multimap.put("lower","e");System.out.println("添加后的lower:"+Joiner.on(",").join(multimap.get("lower")));System.out.println("upper:"+Joiner.on(",").join(multimap.get("upper")));multimap.remove("upper","D");System.out.println("移除元素后的upper:"+Joiner.on(",").join(multimap.get("upper")));System.out.println("是否包含lower-b:"+multimap.containsEntry("lower","b"));System.out.println("是否包含lower-b:"+multimap.containsEntry("lower","f"));System.out.println("是否包含key(upper):"+multimap.containsKey("upper"));System.out.println("是否包含value(c):"+multimap.containsValue("c"));Collection<Map.Entry<String,String>> collection = multimap.entries();System.out.println("MultiMap详情:"+Joiner.on(";").withKeyValueSeparator("=").join(collection));Collection<String> values = multimap.values();System.out.println("MultiMap所有的value:"+Joiner.on(",").join(values));}
(3)、Multimap不是Map

Multimap<K, V>不是Map<K,Collection>,虽然某些Multimap实现中可能使用了map。它们之间的显著区别包括:

  • Multimap.get(key)总是返回非null、但是可能空的集合。这并不意味着Multimap为相应的键花费内存创建了集合,而只是提供一个集合视图方便你为键增加映射值——译者注:如果有这样的键,返回的集合只是包装了Multimap中已有的集合;如果没有这样的键,返回的空集合也只是持有Multimap引用的栈对象,让你可以用来操作底层的Multimap。因此,返回的集合不会占据太多内存,数据实际上还是存放在Multimap中。

  • 如果你更喜欢像Map那样,为Multimap中没有的键返回null,请使用asMap()视图获取一个Map<K, Collection<V>>。(或者用静态方法Multimaps.asMap()为ListMultimap返回一个Map<K, List<V>>。对于SetMultimap和SortedSetMultimap,也有类似的静态方法存在)

  • 当且仅当有值映射到键时,Multimap.containsKey(key)才会返回true。尤其需要注意的是,如果键k之前映射过一个或多个值,但它们都被移除后,Multimap.containsKey(key)会返回false。

  • Multimap.entries()返回Multimap中所有”键-单个值映射”——包括重复键。如果你想要得到所有”键-值集合映射”,请使用asMap().entrySet()。

  • Multimap.size()返回所有”键-单个值映射”的个数,而非不同键的个数。要得到不同键的个数,请改用Multimap.keySet().size()。

(4)、Multimap的各种实现
实现键行为类似值行为类似
ArrayListMultimapHashMapArrayList
HashMultimapHashMapHashSet
LinkedListMultimapLinkedHashMapLinkedList
LinkedHashMultimapLinkedHashMapLinkedHashMap
TreeMultimapTreeMapTreeSet
ImmutableListMultimapImmutableMapImmutableList
ImmutableSetMultimapImmutableMapImmutableSet

除了两个不可变形式的实现,其他所有实现都支持null键和null值

  • LinkedListMultimap.entries()保留了所有键和值的迭代顺序。详情见doc链接。

  • LinkedHashMultimap保留了映射项的插入顺序,包括键插入的顺序,以及键映射的所有值的插入顺序。 请注意,并非所有的Multimap都和上面列出的一样,使用Map<K, Collection<V>>来实现(特别是,一些Multimap实现用了自定义的hashTable,以最小化开销)

3、BiMap

BiMap<K, V>是特殊的Map:

  • 可以用 inverse()反转BiMap<K, V>的键值映射
  • 保证值是唯一的,因此 values()返回Set而不是普通的Collection

在BiMap中,如果你想把键映射到已经存在的值,会抛出IllegalArgumentException异常。

(1)、常用方法
方法描述
V forcePut(String key, V value)对于特定的值,强制替换它的键
BiMap<K,V> inverse()k-v键值对的转换,即v-k
V put<K key,V value>关联v到k
void putAll(Map<? extend k,? extend V> map)将map加入到BiMap
Set values()返回BiMap映射中包含的Collection视图
(2)、BiMap的各种实现
键–值实现值–键实现对应的BiMap实现
HashMapHashMapHashBiMap
ImmutableMapImmutableMapImmutableBiMap
EnumMapEnumMapEnumBiMap
EnumMapHashMapEnumHashBiMap
(3)、示例
    /*** BiMap*/@Testpublic void biMapTest(){BiMap<String, String> biMap = HashBiMap.create();biMap.putAll(ImmutableMap.of("a","1","b","2","c","3","d","4","e","5"));System.out.println("所有的值:"+Joiner.on(",").join(biMap.values()));System.out.println("转换后所有的值:"+Joiner.on(",").join(biMap.inverse().values()));String v = biMap.forcePut("a","10");System.out.println("替换的值:"+v);System.out.println("所有的值:"+Joiner.on(",").join(biMap.values()));}
4、Table

Table是Guava提供的一个接口 Interface Table<R,C,V>,由rowKey+columnKey+value组成 它有两个键,一个值,和一个n行三列的数据表类似,n行取决于Table对对象中存储了多少个数据。

(1)、常用方法
方法描述
Set<Table.Cell<R,C,V>> cellSet()返回集合中的行键,列键,值三元组
void clear()清除所有的键值对
Map<R,V> column(C columnKey)获取列键对应的键值对
Map<C,V> row(R row)获取行键对应的列以及值
Set<C> columnKeySet()获取所有的列键
Set<R> rowKeySet()获取行键
Map<C,Map<R,V>> columnMap返回列键对应的行键-值的视图
boolean contains(Object rowKey,Object columnKey)判断是否包含指定的行键,列键
boolean containsColumn(Object columnKey)判断是否包含指定的列键
boolean containsRow(Object rowKey)判断是否包含指定的行键
boolean containsValue(Object value)判断是否包含值
V get(Object rowKey,Object columnKey)返回指定的行键,列键对应的值,不存在则返回null
boolean isEmpty()判断集合是否为空
V put(Object rowKey,Object columnKey,Object value)put值
void putAll(Table<? extend R,? extend C,? extend V> table)put指定的table
V remove(Object rowKey,Object columnKey)如果有,则移除指定行键,列键
Map<R,Map<C,V>> rowMap()获取每个行键对应的列键,值的视图
int size()集合的个数(行键/列键/值)
Collection<V> values()集合值的集合,包括重复的
(2)、示例
    /*** Table*/@Testpublic void tableTest(){Table<String,String,Integer> table = HashBasedTable.create();table.put("grade_1","class_1",100);table.put("grade_1","class_2",95);table.put("grade_1","class_3",80);table.put("grade_2","class_1",88);table.put("grade_2","class_2",95);table.put("grade_2","class_3",99);table.put("grade_2","class_3",100);Set<Table.Cell<String,String,Integer>> cellSet = table.cellSet();cellSet.forEach(cell -> {System.out.println("table中的行:"+cell.getRowKey()+";列:"+cell.getColumnKey()+";值:"+cell.getValue());});System.out.println("grade1对应的class:"+Joiner.on(";").withKeyValueSeparator("=").join(table.row("grade_1")));System.out.println("class1对应的grade:"+Joiner.on(";").withKeyValueSeparator("=").join(table.column("class_1")));System.out.println("所有的grade:"+Joiner.on(",").join(table.rowKeySet()));System.out.println("所有的class:"+Joiner.on(",").join(table.columnKeySet()));Map<String,Map<String,Integer>> rowMap = table.rowMap();rowMap.forEach((row,map) -> {System.out.println(row +"行对应的列值:"+Joiner.on(";").withKeyValueSeparator("=").join(map));});Map<String,Map<String,Integer>> columnMap = table.columnMap();columnMap.forEach((column,map) -> {System.out.println(column +"列对应的行值:"+Joiner.on(";").withKeyValueSeparator("=").join(map));});System.out.println("是否包含grade_1 和 class_2:"+table.contains("grade_1","class_2"));table.remove("grade_1","class_2");System.out.println("是否包含grade_1 和 class_2:"+table.contains("grade_1","class_2"));}
(3)、Table有如下几种实现:
  • HashBasedTable:本质上用HashMap<R, HashMap<C, V>>实现;

  • TreeBasedTable:本质上用TreeMap<R, TreeMap<C,V>>实现;

  • ImmutableTable:本质上用ImmutableMap<R, ImmutableMap<C, V>>实现;注:ImmutableTable对稀疏或密集的数据集都有优化。

  • ArrayTable:要求在构造时就指定行和列的大小,本质上由一个二维数组实现,以提升访问速度和密集Table的内存利用率。ArrayTable与其他Table的工作原理有点不同。

5、ClassToInstanceMap

ClassToInstanceMap是一种特殊的Map:它的键是类型,而值是符合键所指类型的对象。
为了扩展Map接口,ClassToInstanceMap额外声明了两个方法:T getInstance(Class T) 和T putInstance(Class , T),从而避免强制类型转换,同时保证了类型安全。

ClassToInstanceMap有唯一的泛型参数,通常称为B,代表Map支持的所有类型的上界。

对于ClassToInstanceMap,Guava提供了两种有用的实现:MutableClassToInstanceMap和 ImmutableClassToInstanceMap。

示例
    /*** ClassToInstanceMap*/@Testpublic void classToInstanceMapTest(){ClassToInstanceMap<Number> instanceMap = MutableClassToInstanceMap.create();instanceMap.putInstance(Integer.class,123);instanceMap.putInstance(Long.class,456L);instanceMap.putInstance(Double.class,789.09);System.out.println("Integer:"+instanceMap.getInstance(Integer.class));System.out.println("Long:"+instanceMap.getInstance(Long.class));System.out.println("Double:"+instanceMap.getInstance(Double.class));}
6、RangSet

RangeSet描述了一组不相连的、非空的区间。当把一个区间添加到可变的RangeSet时,所有相连的区间会被合并,空区间会被忽略。

结论

通过深入探索Google Guava库的集合操作,我们不仅仅发现了一个功能强大的工具,更是领略到了一个高效、简洁的Java编程理念。Guava不仅提供了基础数据结构,还为开发者提供了一整套处理集合的利器,从不可变集合到高效工具类,无一不展现出其设计的巧妙之处。

在实际项目中,Guava为我们提供了更清晰、更简单的集合操作方式,帮助我们避免了许多常见的错误和异常。它的性能优化更是让我们在处理大规模数据时事半功倍。

作为Java开发者,我们应该充分了解并灵活运用Guava库,以提高代码的可读性、可维护性和性能。无论是新手还是老手,Guava都能为我们的开发工作带来便捷和效率。

本文已收录于我的个人博客:码农Academy的博客,专注分享Java技术干货,包括Java基础、Spring Boot、Spring Cloud、Mysql、Redis、Elasticsearch、中间件、架构设计、面试题、程序员攻略等

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/620846.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法第十八天-实现Trie(前缀树)

实现Trie&#xff08;前缀树&#xff09; 题目要求 解题思路 本文是前缀入门教程 从二叉树说起 前缀树&#xff0c;也是一种树。为了理解前缀树&#xff0c;我们先从二叉树说起。常见的二叉树结构是下面这样子的&#xff1a; class TreeNode { int val; TreeNode* left; Tre…

CDSP和CISP证书,选择哪个?

&#x1f3af;CDSP和CISP是两种与信息安全领域相关的专业认证。它们有一些相似之处&#xff0c;但也存在一些显著的区别。本文将详细介绍CDSP认证和CISP认证的相同点和区别。 &#x1f451;CDSP和CISP的相同点&#xff1a; 1.行业认可&#xff1a;CDSP和CISP都是行业广泛认可的…

Linux下通过EDAC功能检测PCIE硬件错误

1 EDAC的作用 The edac kernel modules goal is to detect and report hardware errors that occur within the computer system running under linux. 《Documentation/admin-guide/ras.rst》 EDAC可以检测物理内存的错误 和 PCIE的错误&#xff0c;本文主要分析后者。 2 机…

React入门 - 03(初识 React 组件和 JSX)

本章内容 目录 1.初识 React 组件2.关于 JSX 继上一节的工程案例&#xff0c;我们这一节主要了解一下 React组件和 “JSX 语法”。 前置知识点&#xff1a;ES6模块化&继承 1.初识 React 组件 1、打开 src/index.js文件&#xff08;项目的入口文件&#xff09;内容&…

如何使用WinDiff浏览和对比Windows源代码中的符号和系统调用信息

关于WinDiff WinDiff是一款功能强大的Windows二进制源代码安全分析与调试工具&#xff0c;该工具完全开源&#xff0c;基于Web实现其功能&#xff0c;可以帮助广大研究人员在不同版本的操作系统中浏览和对比Microsoft Windows二进制文件的符号、类型和系统调用信息。其中&…

详解HTTPS加密工作过程

&#x1f697;&#x1f697;&#x1f697;今天给大家分享的是HTTPS加密的工作过程。 清风的CSDN博客 &#x1f6e9;️&#x1f6e9;️&#x1f6e9;️希望我的文章能对你有所帮助&#xff0c;有不足的地方还请各位看官多多指教&#xff0c;大家一起学习交流&#xff01; ✈️✈…

PDCA/绩效管理活动

现代绩效管理理论认为&#xff0c;绩效管理活动是一个连续的过程&#xff0c;是指管理者用来确保自己下属员工的工作行为和工作产出与组织的目标保持一致的手段及过程。人们通常用一个循环过程来描述绩效管理的整个过程。我们认为&#xff0c;一个组织的员工绩效管理活动由四个…

基于博弈树的开源五子棋AI教程[6 置换表]

文章目录 引子定义实现讨论与尾记 引子 置换表是记忆化搜索技术的应用&#xff0c;置换表保存了某一盘面的搜索结果。当博弈树搜索遇到相同的局面时可以调用这些信息来减少重复搜索。那么如何设计一个置换表的节点就显得比较重要&#xff0c;本文在经典的置换表节点增加一个显…

NUS CS1101S:SICP JavaScript 描述:一、使用函数构建抽象

原文&#xff1a;1 Building Abstractions with Functions 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 心灵的行为&#xff0c;其中它对简单的想法施加其力量&#xff0c;主要有以下三种&#xff1a;1.将几个简单的想法组合成一个复合的想法&#xff0c;从而形成所…

Scipy 高级教程——稀疏矩阵

Python Scipy 高级教程&#xff1a;稀疏矩阵 Scipy 提供了处理稀疏矩阵的工具&#xff0c;这对于处理大规模数据集中的稀疏数据是非常有效的。本篇博客将深入介绍 Scipy 中的稀疏矩阵功能&#xff0c;并通过实例演示如何应用这些工具。 1. 稀疏矩阵的表示 在 Scipy 中&#…

【重点】【DP】300. 最长递增子序列

题目 更好的方法是耐心排序&#xff0c;参见《算法小抄》的内容&#xff01;&#xff01;&#xff01; 法1&#xff1a;DP 基础解法必须掌握&#xff01;&#xff01;&#xff01; class Solution {public int lengthOfLIS(int[] nums) {if (nums null || nums.length 0) …

【深度学习】RTX2060 2080如何安装CUDA,如何使用onnx runtime

文章目录 如何在Python环境下配置RTX 2060与CUDA 101. 安装最新的NVIDIA显卡驱动2. 使用conda安装CUDA Toolkit3. 验证onnxruntime与CUDA版本4. 验证ONNX需求版本5. 安装ONNX与onnxruntime6. 编写ONNX推理代码 如何在Python环境下配置RTX 2060与CUDA 10 RTX 2060虽然是一款较早…

等保测评是什么

等保测评的全称是信息安全等级保护测评&#xff0c;是经公安部认证的具有资质的测评机构&#xff0c;依据国家信息安全等级保护规范规定&#xff0c;受有关单位委托&#xff0c;按照有关管理规范和技术标准&#xff0c;对信息系统安全等级保护状况进行检测评估的活动。 《信息…

Ps:何时需要转换为智能对象

智能对象 Smart Objects提供了广泛的灵活性和控制能力&#xff0c;特别是在处理复杂的合成、重复元素或需要非破坏性编辑的项目中。 ◆ ◆ ◆ 何时需要转换为智能对象 1、当需要对图像进行缩放、旋转等变换时。 涉及到的 Photoshop 命令包括&#xff1a;变换、自由变换、操控…

windows下如何搭建Yapi环境

今天使用YApi时发现原网址无法访问。这下只能本地部署了&#xff08;官方文档&#xff09;。 第一步&#xff1a;安装node.js 获取资源 nodejs: https://nodejs.org/en/downloadLinux安装yum install -y nodejs查看node版本node -v查看npm版本npm -v第二步&#xff1a;安装mo…

【论文阅读笔记】MobileSal: Extremely Efficient RGB-D Salient Object Detection

1.介绍 MobileSal: Extremely Efficient RGB-D Salient Object Detection MobileSal&#xff1a;极其高效的RGB-D显著对象检测 2021年发表在 IEEE Transactions on Pattern Analysis and Machine Intelligence。 Paper Code 2.摘要 神经网络的高计算成本阻碍了RGB-D显着对象…

Pandas实战100例 | 案例 31: 转换为分类数据

案例 31: 转换为分类数据 知识点讲解 在处理包含文本数据的 DataFrame 时&#xff0c;将文本列转换为分类数据类型通常是一个好主意。这可以提高性能并节省内存。Pandas 允许将列转换为 category 类型。 分类数据类型: category 类型适用于那些只包含有限数量不同值的列&…

【LeetCode】27. 移除元素(简单)——代码随想录算法训练营Day01

题目链接&#xff1a;27. 移除元素 题目描述 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺…

Promise基础详细介绍(一),resolve,reject

Promise的含义 就是一个对象&#xff0c;用来传递异步操作的消息。 基本用法 resolve,reject是javascript引擎提供的。 const promise new Promise(function(resolve, reject) {const result {success: truevalue: 777} //伪代码&#xff0c;比如接口返回的参数if(result.su…

Vue 自定义仿word表单录入之日期输入组件

因项目需要&#xff0c;要实现仿word方式录入数据&#xff0c;要实现鼠标经过时才显示编辑组件&#xff0c;预览及离开后则显示具体的文字。 鼠标经过时显示 正常显示及离开时显示 组件代码 <template ><div class"paper-input flex flex-col border-box "…