关于list:Redis数据结构二ListHashSet及Sorted-Set的结构实现

1 引言之前介绍了Redis的数据存储及String类型的实现,接下来再来看下List、Hash、Set及Sorted Set的数据结构的实现。 2 ListList类型通常被用作异步音讯队列、文章列表查问等;存储有序可反复数据或做为简略的音讯推送机制时,能够应用Redis的List类型。对于这些数据的存储通常会应用链表或者数组作为存储构造。 应用数组存储,随机拜访节点通过索引定位工夫复杂度为O(1)。但在初始化时须要调配间断的内存空间;在减少数据时,如果超过以后调配空间,须要将数据整体搬迁徙到新数组中。应用链表存储,在进行前序遍历或后续遍历,以后节点中要存储前指针和后指针,这两个指针在别离须要8byte共16byte空间存储,存在大量节点会因指针占用过多空间。链表尽管不须要间断空间存储能够进步内存利用率,但频繁的减少和删除操作会使内存碎片化,影响数据读写速率。如果咱们可能将链表和数组的特点联合起来就可能很好解决List类型的数据存储。 2.1 ZipList3.2之前Redis应用的是ZipList,具体构造如下: zlbytes: 4byte 记录整个压缩列表占用的内存字节数:在对压缩列表进行内存重调配, 或者计算 zlend 的地位时应用。zltail:4byte 记录压缩列表表尾节点间隔压缩列表的起始地址有多少字节: 通过这个偏移量,程序毋庸遍历整个压缩列表就能够确定表尾节点的地址。zllen:2byte 记录了压缩列表蕴含的节点数量: 当这个属性的值小于 UINT16\_MAX(65535)时, 这个属性的值就是压缩列表蕴含节点的数量; 当这个值等于UINT16\_MAX 时,节点的实在数量须要遍历整个压缩列表能力计算得出。entry X:压缩列表蕴含的各个节点,节点的长度由节点保留的内容决定。蕴含属性如下:prerawlen:记录前一个节点所占内存的字节数,不便查找上一个元素地址len:data依据len的首个byte选用不同的数据类型来存储datadata:本元素的信息zlend: 尾节点 恒等于255ziplist是一个间断的内存块,由表头、若干个entry节点和压缩列表尾部标识符zlend组成,通过一系列编码规定,进步内存的利用率,应用于存储整数和短字符串。每次减少和删除数据时,所有数据都在同一个ziplist中都会进行搬移操作。如果将一个组数据按阈值进行拆分出多个数据,就能保障每次只操作某一个ziplist。3.2之后应用的quicklist与ziplist。 2.2 QuickListquicklist就是保护了一种宏观上的双端链表(相似于B树),链表的节点为对ziplist包装的quicklistNode,每个quciklistNode都会通过前后指针互相指向,quicklist蕴含头、尾quicklistNode的指针。 typedef struct quicklist {quicklistNode *head;quicklistNode *tail;unsigned long count; /* total count of all entries in all ziplists */unsigned long len; /* number of quicklistNodes */int fill : QL_FILL_BITS; /* fill factor for individual nodes */unsigned int compress : QL_COMP_BITS; /* depth of end nodes not to compress;0=off */...} quicklist;*head:表头节点*tail:表尾节点count:节点蕴含entries数量len:quicklistNode节点计数器fill:保留ziplist的大小,配置文件设定compress:保留压缩水平值,配置文件设定quicklistNode: ...

October 26, 2022 · 3 min · jiezi

关于list:java-List分页取值

/** * 利用subList办法进行分页 * * @param list 分页数据 * @param pagesize 页面大小 * @param currentPage 以后页面 */private List pageBySubList(List list, int pagesize, int currentPage) { int totalcount = list.size(); int pagecount = 0; List<String> subList; int m = totalcount % pagesize; if (m > 0) { pagecount = totalcount / pagesize + 1; } else { pagecount = totalcount / pagesize; } if (m == 0) { subList = list.subList((currentPage - 1) * pagesize, pagesize * (currentPage)); } else { if (currentPage == pagecount) { subList = list.subList((currentPage - 1) * pagesize, totalcount); } else { subList = list.subList((currentPage - 1) * pagesize, pagesize * (currentPage)); } } return subList;}

October 21, 2022 · 1 min · jiezi

关于list:我要在for循环List中删除元素

前言:for循环能够删除汇合元素吗,往往咱们失去的答案有时候就是不能够,平安起见,要迭代器,包含我在阿里的开发标准里也写了这么一句话, 不要在 foreach 循环里进行元素的 remove / add 操作。remove 元素请应用 iterator 形式,如果并发操作,须要对 iterator 对象加锁  仍然记得刚来第三天写个接口我就for循环内删除元素,过后很沙雕,恰好又被代码走查看到了,难堪的我挖了个洞将for改成了迭代器形式遍历,这两天看个大佬的代码,他就是for循环并remove其中元素,我开心的认为发现了一个bug,嗯,再往下看不对,这代码妙啊,百度了一下,有了这篇文章 上面咱们通过几个例子以及剖析源码的形式来看看问题,nice 问题一List<String> list = new ArrayList();list.add("111");list.add("222");list.add("222");list.add("333");list.add("222");list.add("555");//list.stream().forEach(System.out::println);for(int i = 0;i < list.size();i++){ if(StrUtil.equals("222",list.get(i))){ list.remove(i); }}咱们先看下下面这个用例,这个后果是啥呢?是111 222 333 555,咦,明明等于222的移除了啊,怎么没移掉,而且还没报错,通常咱们移除元素会报错呀,其实这种for办法在咱们循环遍历的时候list.remove(i);会删除对应的元素不会报错,然而呢,删除的元素地位会空进去,前面的元素会往前移一位,这样如果有两个元素的地位是间断的话,那么前面这个元素是不会进行判断的,这样就不会合乎咱们的剖析场景的, 咱们按代码程序翻一下,索引在范畴内,则获取remove的元素,而后将list的元素大小减一,如果还存在,就进行元素的copy,从源数组的index+1地位开始要复制的数组元素的数量numMoved,到指标数组的指定地位,而后通过GC将最初一个地位内存回收,哦。原来是这样的,至于说的报错咱们上面在剖析 问题二for (String ll : list) { if(StrUtil.equals(ll,"333")){ list.remove(ll); }}如上代码,当咱们应用foreach的时候咱们须要remove的是一个对象,而不是for时的下标,这里会报错java.util.ConcurrentModificationException,这就是咱们说的报错了,我先把后果说了吧,这里咱们删除元素的话其实并不会报错,报错的是for循环哪里,在你remove后下一次遍历的时候才会报错,报异样的办法是java.util.ArrayList$Itr.checkForComodification,一看就是办法里的迭代器报错 一个是删除后元素地位前挪了导致间断相等的元素判断不到一个是删除元素后改变的次数变得和冀望变动的次数不一样了导致的这些异样信息for(int i = list.size()-1;i>=0;i--){ if(StrUtil.equals("222",list.get(i))){ String remove = list.remove(i); System.out.println("shanchu"+ remove); }}

April 4, 2022 · 1 min · jiezi

关于list:大数据列表渲染系列二极简实现

本节,咱们实现一个极简版的虚构列表,固定尺寸的虚构列表,麻雀虽小,却是五脏俱全哦! 需要实现一个固定尺寸的虚构渲染列表组件,props属性如下: props: { width: number; height: number; itemCount: number; itemSize: number;}应用形式: const Row = (..args) => (<div className="Row"></div>);<List className={"List"} width={300} height={300} itemCount={10000} itemSize={40}> {Row}</List>实现什么技术栈都能够,这里我的项目应用的react,那就选用react来实现。 初始化我的项目应用create-react-app初始化一个利用,而后启动,清理掉demo的代码。 虚构列表依据上一节的剖析,咱们核心技术实现是 一个render渲染函数,用来渲染数据;一个onScroll函数监听滚动事件,去更新 数据区间[startIndex, endIndex],而后从新render。大略伪代码如下: class List extends React.PureComponent { state = {}; render() {}; onScroll() {};}接下来咱们进行细节填充实现,首先咱们须要依据数据渲染出第一屏初始化的dom,即要先实现render函数逻辑,咱们采纳相对定位的形式进行dom排版。 render() { // 从props解析属性 const { children, width, height, itemCount, layout, itemKey = defaultItemKey, } = this.props; // 预留方向设定属性 const isHorizontal = layout === "horizontal"; // 假如有一个函数_getRangeToRender能够帮咱们计算出 渲染区间 const [startIndex, stopIndex] = this._getRangeToRender(); const items = []; if (itemCount > 0) { // 循环创立元素 for (let index = startIndex; index <= stopIndex; index++) { items.push( createElement(children, { data: {}, key: itemKey(index), index, style: this._getItemStyle(index), // 帮忙计算dom的地位款式 }) ); } } // 假如getEstimatedTotalSize函数能够帮忙咱们计算出总尺寸 const estimatedTotalSize = getEstimatedTotalSize( this.props, ); return createElement( "div", { onScroll: this.onScroll, style: { position: "relative", height, width, overflow: "auto", WebkitOverflowScrolling: "touch", willChange: "transform", }, }, createElement("div", { children: items, style: { height: isHorizontal ? "100%" : estimatedTotalSize, pointerEvents: "none", width: isHorizontal ? estimatedTotalSize : "100%", }, }) );}OK,到了这里render函数的逻辑就写完了,是不是超级简略。接下来咱们实现以下 render函数外面应用到的辅助函数. ...

April 25, 2021 · 4 min · jiezi

如何线程安全地遍历List

遍历List的多种方式在讲如何线程安全地遍历 List 之前,先看看遍历一个 List 通常会采用哪些方式。 方式一:for(int i = 0; i < list.size(); i++) { System.out.println(list.get(i));}方式二:Iterator iterator = list.iterator();while(iterator.hasNext()) { System.out.println(iterator.next());}方式三:for(Object item : list) { System.out.println(item);}方式四(Java 8):list.forEach(new Consumer<Object>() { @Override public void accept(Object item) { System.out.println(item); }});方式五(Java 8 Lambda):list.forEach(item -> { System.out.println(item);});方式一的遍历方法对于 RandomAccess 接口的实现类(例如 ArrayList)来说是一种性能很好的遍历方式。但是对于 LinkedList 这样的基于链表实现的 List,通过 list.get(i) 获取元素的性能差。 方式二和方式三两种方式的本质是一样的,都是通过 Iterator 迭代器来实现的遍历,方式三是增强版的 for 循环,可以看作是方式二的简化形式。 方式四和方式五本质也是一样的,都是使用Java 8新增的 forEach 方法来遍历。方式五是方式四的一种简化形式,使用了Lambda表达式。 遍历List的同时操作List会发生什么?先用非线程安全的 ArrayList 做个试验,用一个线程通过增强的 for 循环遍历 List,遍历的同时另一个线程删除 List 中的一个元素,代码如下: ...

November 3, 2019 · 3 min · jiezi

阿里巴巴资深技术专家雷卷值得开发者关注的-Java-8-后时代的语言特性

首先我们必须承认,Java 8 是一个里程碑式的版本,这个相信大多数Java程序员都认同,其中最知名的是 Streams & Lambda ,这让 Functional Programming 成为可能,让 Java 换发新的活力。这也是即便 Oracle 不在支持 Java 8 的更新,各个云厂商还是积极支持,站点为https://adoptopenjdk.net/,可以让 Java 8 能继续保留非常长的时间。 目前非常多的同学日常开发并没有切换到 Java 8 后续的版本,所以这篇文章,我们打算写一个后 Java 8 时代的特性,主要是偏向于开发的,不涉及 GC , Compiler , Java Module , Platform 等,如果一一解释,估计非常长的文章,当然后续可以写另外文章介绍。下面的这些特性会影响到我们日常的代码编写。 考虑到 Java 13 马上发布,所以版本覆盖从 9 到 13 ,与此同时 Java Release 的方式调整,一些特性是在某一版本引入(preview),后续收到反馈后做了非常多的增强和完善,这里就不一一说明特性是哪个版本的,你可以理解为后Java 8版本后的特性大杂烩。参考资料来源于官方 features 和 pluralsight 上每一个版本的 Java 特性介绍。 var 关键字(局部变量类型推导) Local-Variable Type InferenceJava 支持泛型,但是如果类型非常长,你又不是特别关注,你用 var 关键字就可以啦,可以让你代码非常简洁。Java IDE 都非常好地支持 var,不用担心代码提示等问题。 Map<String, List<Map<String,Object>>> store = new ConcurrentHashMap<String, List<Map<String,Object>>>(); Map<String, List<Map<String,Object>>> store = new ConcurrentHashMap<>(); Map<String, List<Map<String,Object>>> store = new ConcurrentHashMap<String, List<Map<String,Object>>>(); //lambda BiFunction<String, String, String> function1 = (var s1, var s2) -> s1 + s2; System.out.println(function1.apply(text1, text2));复制 confd 文件到 bin 目录下,启动 confd ...

September 9, 2019 · 2 min · jiezi

ArrayList-线程安全性学习

引言最近学校的氛围比较活跃,考研的复习,不考研的都在写简历准备面试。 看了看,最近也没有好公司来办宣讲会,也就没了投简历的意向。最近看了看面试题,想着补一补基础,以后面几家Spring Cloud的企业,去和面试官交流交流。 Spring Cloud的学习与体会 最近看了《Spring Cloud微服务实战》一书,感觉受益匪浅,大有裨益。 高并发应用,必须是要启用Spring Cloud的。有了Spring Cloud,就不用再像之前一样,前端工程师团队,后端工程师团队,运维团队。而是按模块划分,订单模块团队,支付模块团队,每个团队里都是从前端到后台到运维的全栈工程师。 就像上次黄庭祥说的,ThinkPHP开发,他写学期管理;AngularJS开发,他又写学期管理;Angular开发,他还写学期管理。想到什么了么?肯定精通这个模块的业务逻辑啊? 如果培养出优秀的支付模块团队、优秀的安全模块团队、优秀的高并发优化团队,其实淘宝也不过如此。 相互的依赖,从原来的@Autowired转为服务器接口间的调用。每个模块都是一个Spring Cloud应用,各应用间通过互相调用、相互协作共同实现业务功能,同时,各应用模块可以采用不同的数据库,以发挥各数据库之所长。 然后后台分布式部署,到了并发的时候,给相应的模块加服务器负载均衡就是了。个人中心模块,不常用,两个服务器负载;订单模块,可能会并发,加个百十来个服务器负载均衡。当然,像618、双十一这样的场景,肯定不是加服务器就能解决的,我这里只是举个简单的例子。模块划分之后,可以有针对性地解决高并发问题。 不扯淡了,开始进入正题。 面试题再谈线程安全什么是线程安全? 我看到这道题就感觉怎么也说不出来,就是多线程的环境下运行,我这个应用也不炸,虽然是这个意思,但是也不能这样回答啊?一时之间,找不到相关的学术词汇回答此问题。 这是想了许久后,我自己总结出的回答: 程序在单线程环境下正常执行得到了正确的结果,在多个线程并发执行的环境条件下,仍然能得到像单线程一样正确的结果,这就是线程安全。 如果一个类(或对象),我们在使用时,无需考虑任何多线程相关的问题,就像单线程一样使用,且最后能得到正确的结果,那就说这个类(或对象)是线程安全的。 ArrayList线程安全吗?看了许多面试题,发现面试官都喜欢以一个小方面进行切入,然后无限扩展,直到把面试者问懵圈为止。 ArrayList线程安全吗? 虽然天天用ArrayList,但是真的没考虑过这个问题。其实,ArrayList线程不安全。 ArrayList是一个内部采用数组实现的线性表,它相比数组最大的优点就是使用时可以不用去像数组一样new的时候去考虑要容纳多少个元素。ArrayList默认构造一个容量为10的数组。 private static final int DEFAULT_CAPACITY = 10;如果容量不够了,ArrayList会自动扩容,扩容至原来的1.5倍。(右移一位,相当于除以2)。 int newCapacity = oldCapacity + (oldCapacity >> 1);ArrayList没有对多线程问题进行处理,举个add方法的例子就能证明它线程不安全。 elementData[size++] = e;别看这是一行,其实是执行了两步操作,赋值和自增。 线程A add一个元素,然后暂停执行,size还没自增,然后线程B再add元素,size没变,就直接把A add的元素覆盖了。 不安全为什么要使用?又回到了之前向晨澍请教的问题,线程安全,必然是有额外开销的。 所以List的三个接口ArrayList、LinkedList和Vector。 线程不安全的要比线程安全的执行效率高。所以我们常用的是线程不安全的ArrayList、LinkedList,而从来没有用过线程安全的Vector。 Vector自JDK1.0就存在,设计得不够完善,多线程情况下如果使用不当也会发生错误,不推荐使用。 如何解决线程不安全既然Vector不能用,那我就想要一个线程安全的List得怎么整呢? 调用Collections.synchronizedList方法,使ArrayList线程安全。 List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());返回SynchronizedList类的对象,经典的装饰器模式,对方法访问加了同步。 public void add(int index, E element) { synchronized (mutex) {list.add(index, element);}}public E remove(int index) { synchronized (mutex) {return list.remove(index);}}总结何处望神州?满眼风光北固楼。千古兴亡多少事?悠悠。不尽长江滚滚流。年少万兜鍪,坐断东南战未休。天下英雄谁敌手?曹刘。生子当如孙仲谋。 ...

May 11, 2019 · 1 min · jiezi

一步步实现一个自适应的react-native拖拽排序

2019.2: 优化拖拽不移动时自动恢复,现在这个插件应该没有任何问题。新加一个实战演示例子,后面有时间会对这个例子进行加动画,删除时item向下到待选的item动画,和待选到item。还有滑动时自动向下滑动动画。最近由于业务需求需要实现一个功能需要实现图片的上传和排序和删除,在网上搜索了几款发现都需要固定列数,感觉不太友好,所以自己实现了一个可以不需要设定列数的排序,而且布局高度实现自适应。源码链接效果图对比(固定列数和自适应流布局)![[图片上传中…(iphone.jpg-9f7224-1533711885416-0)]](https://user-gold-cdn.xitu.io…动态图实现其实拖拽排序在大多数编程语言里已经有很多中三方插件可以使用,实现方法都差不多,而且例如Android和iOS或者现在的React-Native他们逻辑几乎是可以共用,你会写一个语言的拖拽排序,其他的都差不多。梳理一下步骤开始触发: 长按或触摸到达一定时间时触发开始排序,这时可以进行把被单机的item放大、透明、抖动动画。开始滑动:(1) 被拖拽的item随着手指的滑动而滑动(2) 被拖动的item滑动到第x个时,item到x之间的item进行左滑右滑一个位置的动画。松开手指:(1) 被拖拽的这个item通过四舍五入进入相应的位置。(2) 数据进行替换并重绘加布局矫正。tip: 滑动逻辑,例如当你把index=1拖到index=3,不是将1和3替换(0,3,2,1,4),而是(0,3,1,2,4)这才是拖拽后结果,只将被拖拽的一个替换到要去的位置,其他的向前和向后移动主要代码// 触摸事件的监听this._panResponder = PanResponder.create({ onStartShouldSetPanResponder: (evt, gestureState) => this.props.sortable, onStartShouldSetPanResponderCapture: (evt, gestureState) => { this.isMovePanResponder = false return false }, // 接管触摸加滑动事件 onMoveShouldSetPanResponder: (evt, gestureState) => this.isMovePanResponder, onMoveShouldSetPanResponderCapture: (evt, gestureState) => this.isMovePanResponder, onPanResponderGrant: (evt, gestureState) => {}, onPanResponderMove: (evt, gestureState) => this.moveTouch(evt,gestureState), onPanResponderRelease: (evt, gestureState) => this.endTouch(evt), onPanResponderTerminationRequest: (evt, gestureState) => false, onShouldBlockNativeResponder: (evt, gestureState) => false, })//这里使用长按触发开发拖拽事件,其实开始是使用触摸一定时间后触发事件的,但和View的单机事件有冲突不好解决,所以选择了长按触发事件startTouch(touchIndex) { // 接管滑动 this.isMovePanResponder = true //if (this.measureTimeOut) clearTimeout(this.measureTimeOut) if (sortRefs.has(touchIndex)) { if (this.props.onDragStart) { this.props.onDragStart(touchIndex) } //变大和加透明 Animated.timing( this.state.dataSource[touchIndex].scaleValue, { toValue: maxScale, duration: scaleDuration, } ).start(()=>{ // 备份被触摸的事件 this.touchCurItem = { ref: sortRefs.get(touchIndex), index: touchIndex, // 记录之前的位置 originLeft: this.state.dataSource[touchIndex].originLeft, originTop: this.state.dataSource[touchIndex].originTop, moveToIndex: touchIndex, } }) } }//滑动moveTouch (nativeEvent,gestureState) { if (this.touchCurItem) { let dx = gestureState.dx let dy = gestureState.dy const rowNum = parseInt(this.props.parentWidth/this.itemWidth); const maxWidth = this.props.parentWidth-this.itemWidth const maxHeight = this.itemHeightMath.ceil(this.state.dataSource.length/rowNum) - this.itemHeight //出界后取最大或最小值防止出界 if (this.touchCurItem.originLeft + dx < 0) { dx = -this.touchCurItem.originLeft } else if (this.touchCurItem.originLeft + dx > maxWidth) { dx = maxWidth - this.touchCurItem.originLeft } if (this.touchCurItem.originTop + dy < 0) { dy = -this.touchCurItem.originTop } else if (this.touchCurItem.originTop + dy > maxHeight) { dy = maxHeight - this.touchCurItem.originTop } let left = this.touchCurItem.originLeft + dx let top = this.touchCurItem.originTop + dy //置于最上层 this.touchCurItem.ref.setNativeProps({ style: { zIndex: touchZIndex, } }) //滑动时刷新布局,这里直接刷新Animated的数字就可以进行局部刷新了this.state.dataSource[this.touchCurItem.index].position.setValue({ x: left, y: top, }) let moveToIndex = 0 let moveXNum = dx/this.itemWidth let moveYNum = dy/this.itemHeight if (moveXNum > 0) { moveXNum = parseInt(moveXNum+0.5) } else if (moveXNum < 0) { moveXNum = parseInt(moveXNum-0.5) } if (moveYNum > 0) { moveYNum = parseInt(moveYNum+0.5) } else if (moveYNum < 0) { moveYNum = parseInt(moveYNum-0.5) } moveToIndex = this.touchCurItem.index+moveXNum+moveYNumrowNum if (moveToIndex > this.state.dataSource.length-1) moveToIndex = this.state.dataSource.length-1 // 其他item向左和向右滑动 if (this.touchCurItem.moveToIndex != moveToIndex ) { this.touchCurItem.moveToIndex = moveToIndex this.state.dataSource.forEach((item,index)=>{ let nextItem = null if (index > this.touchCurItem.index && index <= moveToIndex) { nextItem = this.state.dataSource[index-1] } else if (index >= moveToIndex && index < this.touchCurItem.index) { nextItem = this.state.dataSource[index+1] } else if (index != this.touchCurItem.index && (item.position.x._value != item.originLeft || item.position.y._value != item.originTop)) { nextItem = this.state.dataSource[index] //有时前一个或者后一个数据有个动画差的原因无法回到正确位置,这里进行矫正 } else if ((this.touchCurItem.index-moveToIndex > 0 && moveToIndex == index+1) || (this.touchCurItem.index-moveToIndex < 0 && moveToIndex == index-1)) { nextItem = this.state.dataSource[index] } //需要滑动的就进行滑动动画 if (nextItem != null) { Animated.timing( item.position, { toValue: {x: parseInt(nextItem.originLeft+0.5),y: parseInt(nextItem.originTop+0.5)}, duration: slideDuration, easing: Easing.out(Easing.quad), } ).start() } }) } } }//触摸事件 endTouch (nativeEvent) { //clear if (this.measureTimeOut) clearTimeout(this.measureTimeOut) if (this.touchCurItem) { if (this.props.onDragEnd) { this.props.onDragEnd(this.touchCurItem.index,this.touchCurItem.moveToIndex) } //this.state.dataSource[this.touchCurItem.index].scaleValue.setValue(1) Animated.timing( this.state.dataSource[this.touchCurItem.index].scaleValue, { toValue: 1, duration: scaleDuration, } ).start() this.touchCurItem.ref.setNativeProps({ style: { zIndex: defaultZIndex, } }) this.changePosition(this.touchCurItem.index,this.touchCurItem.moveToIndex) this.touchCurItem = null } }//刷新数据 changePosition(startIndex,endIndex) { if (startIndex == endIndex) { const curItem = this.state.dataSource[startIndex] this.state.dataSource[startIndex].position.setValue({ x: parseInt(curItem.originLeft+0.5), y: parseInt(curItem.originTop+0.5), }) return; } let isCommon = true if (startIndex > endIndex) { isCommon = false let tempIndex = startIndex startIndex = endIndex endIndex = tempIndex } const newDataSource = […this.state.dataSource].map((item,index)=>{ let newIndex = null if (isCommon) { if (endIndex > index && index >= startIndex) { newIndex = index+1 } else if (endIndex == index) { newIndex = startIndex } } else { if (endIndex >= index && index > startIndex) { newIndex = index-1 } else if (startIndex == index) { newIndex = endIndex } } if (newIndex != null) { const newItem = {…this.state.dataSource[newIndex]} newItem.originLeft = item.originLeft newItem.originTop = item.originTop newItem.position = new Animated.ValueXY({ x: parseInt(item.originLeft+0.5), y: parseInt(item.originTop+0.5), }) item = newItem } return item }) this.setState({ dataSource: newDataSource },()=>{ if (this.props.onDataChange) { this.props.onDataChange(this.getOriginalData()) } //防止RN不绘制开头和结尾 const startItem = this.state.dataSource[startIndex] this.state.dataSource[startIndex].position.setValue({ x: parseInt(startItem.originLeft+0.5), y: parseInt(startItem.originTop+0.5), }) const endItem = this.state.dataSource[endIndex] this.state.dataSource[endIndex].position.setValue({ x: parseInt(endItem.originLeft+0.5), y: parseInt(endItem.originTop+0.5), }) }) }后续会加上添加和删除Item渐变动画源码链接 ...

March 18, 2019 · 3 min · jiezi

Stream流与Lambda表达式(一) 杂谈

一、流 转换为数组、集合package com.java.design.java8.Stream;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;import java.util.ArrayList;import java.util.List;import java.util.stream.Stream;/** * @author 陈杨 /@SpringBootTest@RunWith(SpringRunner.class)public class ListChange { private Stream<String> stream = Stream.of(“Kirito”, “Asuna”, “Illyasviel”, “Sakura”); @Test public void testListChange() { // 将流转换为数组 // System.out.println("————-将流转换为数组—————"); // String[] array = stream.toArray(len -> new String[len]); // String[] array = stream.toArray(String[]::new); // Arrays.asList(array).stream().forEach(System.out::println); // 将流转换为集合 // System.out.println("————-将流转换为集合—————"); // System.out.println("——-Collectors.toList()解析———–"); / public static <T> * Collector<T, ?, List<T>> toList() { * return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add, * (left, right) -> { left.addAll(right); return left; }, * CH_ID); }/ // List<String> list = stream.collect(Collectors.toList()); // List<String> linkedList = stream.collect(LinkedList::new,LinkedList::add,LinkedList::addAll); List<String> list = stream.collect(ArrayList::new, ArrayList::add, ArrayList::addAll); list.forEach(System.out::println); System.out.println(list.getClass()); // System.out.println("——-Collectors.toCollection()解析—–"); / public static <T, C extends Collection<T>> * Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) { * return new CollectorImpl<>(collectionFactory, Collection<T>::add, * (r1, r2) -> { r1.addAll(r2); return r1; }, * CH_ID); }*/ // List<String> list =stream.collect(Collectors.toCollection(ArrayList::new)); // List<String> linkedList =stream.collect(Collectors.toCollection(ArrayList::new)); // Set<String> treeSet =stream.collect(Collectors.toCollection(TreeSet::new)); // Set<String> hashSet =stream.collect(Collectors.toCollection(HashSet::new)); }} . ____ _ __ _ _ /\ / ’ __ _ () __ __ _ \ \ \ ( ( )__ | ‘_ | ‘| | ‘ / | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.2.RELEASE)2019-02-20 15:47:22.310 INFO 1348 --- [ main] com.java.design.java8.Stream.ListChange : Starting ListChange on DESKTOP-87RMBG4 with PID 1348 (started by 46250 in E:\IdeaProjects\design)2019-02-20 15:47:22.311 INFO 1348 --- [ main] com.java.design.java8.Stream.ListChange : No active profile set, falling back to default profiles: default2019-02-20 15:47:22.947 INFO 1348 --- [ main] com.java.design.java8.Stream.ListChange : Started ListChange in 0.914 seconds (JVM running for 1.774)KiritoAsunaIllyasvielSakuraclass java.util.ArrayList二、集合排序package com.java.design.java8.Stream;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;import java.util.*;/** * @author 陈杨 */@SpringBootTest@RunWith(SpringRunner.class)public class ComparatorDetail { private List&lt;String&gt; names; @Before public void init() { names = Arrays.asList("Kirito", "Asuna", "Sinon", "Yuuki", "Alice"); } public void println() { System.out.println(names); System.out.println("-----------------------------------------\n"); } @Test public void testComparatorDetail() { // 对名字进行升序排序 Collections.sort(names); this.println(); // 对名字进行降序排序 names.sort(Collections.reverseOrder()); this.println(); // 按照姓名的字符串长度升序排序 相同长度--&gt;比较前两个字符--&gt;按照字符的ASCII码大小升序排序 names.sort(Comparator.comparingInt(String::length) .thenComparing(str -&gt; str.charAt(0)) .thenComparing(str -&gt; str.charAt(1)) ); this.println(); // 按照姓名的字符串长度降序排序 相同长度--&gt;比较前两个字符--&gt;按照字符的ASCII码大小降序排序 names.sort(Comparator.comparingInt(String::length) .thenComparing(str -&gt; str.charAt(0)) .thenComparing(str -&gt; str.charAt(1)) .reversed()); this.println(); // 按照姓名的字符串长度降序排序 相同长度--&gt;按照字符的ASCII码大小排序(不区分大小写) names.sort(Comparator.comparingInt(String::length) .thenComparing(String.CASE_INSENSITIVE_ORDER)); this.println(); }} . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \( ( )\___ | '_ | '_| | '_ \/ _ | \ \ \ \ \/ )| |)| | | | | || (| | ) ) ) ) ’ || .__|| ||| |_, | / / / / =========||==============|/=//// :: Spring Boot :: (v2.1.2.RELEASE)2019-02-20 15:58:39.959 INFO 4588 — [ main] c.j.d.java8.Stream.ComparatorDetail : Starting ComparatorDetail on DESKTOP-87RMBG4 with PID 4588 (started by 46250 in E:\IdeaProjects\design)2019-02-20 15:58:39.962 INFO 4588 — [ main] c.j.d.java8.Stream.ComparatorDetail : No active profile set, falling back to default profiles: default2019-02-20 15:58:40.459 INFO 4588 — [ main] c.j.d.java8.Stream.ComparatorDetail : Started ComparatorDetail in 0.729 seconds (JVM running for 1.462)[Alice, Asuna, Kirito, Sinon, Yuuki]—————————————–[Yuuki, Sinon, Kirito, Asuna, Alice]—————————————–[Alice, Asuna, Sinon, Yuuki, Kirito]—————————————–[Kirito, Yuuki, Sinon, Asuna, Alice]—————————————–[Alice, Asuna, Sinon, Yuuki, Kirito]—————————————–三、Stream之map(Lambda)package com.java.design.java8.Stream;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;import java.util.Arrays;import java.util.Collections;import java.util.List;import java.util.stream.Collectors;/** * @author 陈杨 /@SpringBootTest@RunWith(SpringRunner.class)public class StringOperation { private List<String> list = Arrays.asList(“Kirito”, “Asuna”, “Illyasviel”, “Sakura”); private List<List<String>> listMap = Arrays.asList(Collections.singletonList(“Kirito”), Collections.singletonList(“Asuna”), Collections.singletonList(“Illyasviel”), Collections.singletonList(“Sakura”)); private List<List<String>> listFlatMap = Arrays.asList(Collections.singletonList(“Kirito”), Collections.singletonList(“Asuna”), Collections.singletonList(“Illyasviel”), Collections.singletonList(“Sakura”)); @Test public void testStringOperation() { // 集合中 每个字符串 按照排列先后顺序拼接 形成一个长字符串 // String concat = // list.stream().collect(StringBuilder::new, StringBuilder::append, StringBuilder::append).toString(); // String concat = list.stream().collect(Collectors.joining()); // System.out.println(concat); // 集合中 对每个字符串元素 将所有字母变成大写字母 System.out.println("—————————————–\n"); List<String> upperCase = list.stream().map(String::toUpperCase).collect(Collectors.toList()); upperCase.forEach(System.out::println); // 集合中 对每个字符串元素 将所有字母变成小写字母 System.out.println("—————————————–\n"); List<String> lowerCase = list.stream().map(String::toLowerCase).collect(Collectors.toList()); lowerCase.forEach(System.out::println); System.out.println("—————————————–\n"); System.out.println(“FlatMap与Map的区别:\n”); // map: 对多个list 分别map Fuction 映射 形成多个list System.out.println("—————————————–\n"); System.out.println(“进行map映射:”); List<List<String>> upperMap = listMap.stream() .map(list -> list.stream().map(String::toUpperCase) .collect(Collectors.toList())).collect(Collectors.toList()); upperMap.forEach(System.out::println); // FlatMap: 对多个list 进行flat扁平化 后再进行map Fuction 映射 形成一个list System.out.println("—————————————–\n"); System.out.println(“FlatMap扁平化进行map映射:”); List<String> upperFlatMap = listFlatMap.stream() .flatMap(list -> list.stream().map(String::toUpperCase)).collect(Collectors.toList()); upperFlatMap.forEach(System.out::println); }} . ____ _ __ _ _ /\ / ’ __ _ () __ __ _ \ \ \ ( ( )__ | ‘_ | ‘| | ‘ / | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.2.RELEASE)2019-02-20 15:50:07.423 INFO 8208 --- [ main] c.j.design.java8.Stream.StringOperation : Starting StringOperation on DESKTOP-87RMBG4 with PID 8208 (started by 46250 in E:\IdeaProjects\design)2019-02-20 15:50:07.424 INFO 8208 --- [ main] c.j.design.java8.Stream.StringOperation : No active profile set, falling back to default profiles: default2019-02-20 15:50:07.917 INFO 8208 --- [ main] c.j.design.java8.Stream.StringOperation : Started StringOperation in 0.717 seconds (JVM running for 1.5)-----------------------------------------KIRITOASUNAILLYASVIELSAKURA-----------------------------------------kiritoasunaillyasvielsakura-----------------------------------------FlatMap与Map的区别:-----------------------------------------进行map映射:[KIRITO][ASUNA][ILLYASVIEL][SAKURA]-----------------------------------------FlatMap扁平化进行map映射:KIRITOASUNAILLYASVIELSAKURA四、内部迭代与外部迭代package com.java.design.java8.Stream;import com.java.design.java8.entity.Student;import com.java.design.java8.entity.Students;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;import java.util.*;/** * @author 陈杨 */@SpringBootTest@RunWith(SpringRunner.class)//迭代本质public class IterativeEssence { private List&lt;Student&gt; students; @Before public void init() { students = new Students().init(); } @Test public void testIterativeEssence() { // 需求: select name from students where age &gt; 14 and addr ="Sword Art Online" order by id desc ; // 外部迭代 System.out.println("-----------------------------------------\n"); System.out.println("外部迭代"); List&lt;Student&gt; list = new ArrayList&lt;&gt;(); for (Student student : students) { if (student.getAge() &gt; 14 &amp;&amp; student.getAddr().equals("Sword Art Online")) { list.add(student); } } list.sort(Comparator.comparingInt(Student::getId)); for (Student student : list) { System.out.println(student.getName()); } // 内部迭代 System.out.println("-----------------------------------------\n"); System.out.println("内部迭代"); students.stream() .filter(student -&gt; student.getAge() &gt; 14) .filter(student -&gt; student.getAddr().equals("Sword Art Online")) .sorted(Comparator.comparingInt(Student::getId)). forEach(student -&gt; System.out.println(student.getName())); // 备注: // 内部迭代与SQL语句属于描述性语言 // 集合关注的是数据与数据存储 // 流关注的是数据的计算 // 流中间操作返回的都是Stream对象 泛型取决于中间操作的类型 // 流终止操作: 无返回值(forEach) 返回值是其他类型 }} . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \( ( )\___ | '_ | '_| | '_ \/ _ | \ \ \ \ \/ )| |)| | | | | || (| | ) ) ) ) ’ || .__|| ||| |_, | / / / / =========||==============|/=//// :: Spring Boot :: (v2.1.2.RELEASE)2019-02-20 15:53:03.633 INFO 8864 — [ main] c.j.d.java8.Stream.IterativeEssence : Starting IterativeEssence on DESKTOP-87RMBG4 with PID 8864 (started by 46250 in E:\IdeaProjects\design)2019-02-20 15:53:03.640 INFO 8864 — [ main] c.j.d.java8.Stream.IterativeEssence : No active profile set, falling back to default profiles: default2019-02-20 15:53:04.167 INFO 8864 — [ main] c.j.d.java8.Stream.IterativeEssence : Started IterativeEssence in 0.746 seconds (JVM running for 1.455)—————————————–外部迭代KiritoAsuna—————————————–内部迭代KiritoAsuna五、串行流与并行流 简单性能测试package com.java.design.java8.Stream;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import java.util.UUID;import java.util.concurrent.TimeUnit;import java.util.function.Function;import java.util.stream.Collectors;import java.util.stream.IntStream;/* * @author 陈杨 /@RunWith(SpringRunner.class)@SpringBootTestpublic class ErgodicString { private List<String> uuid; private long startTime; private long endTime; private long parallelEndTime; @Before public void init() { uuid = new ArrayList<>(10000000); IntStream.range(0, 10000000).forEach(i -> uuid.add(UUID.randomUUID().toString())); } public void testNormal() { startTime = System.nanoTime(); uuid.stream().sorted().collect(Collectors.toList()); endTime = System.nanoTime(); long millis = TimeUnit.NANOSECONDS.toMillis(endTime - startTime); System.out.println(“单线程” + millis); } public void testParallel() { startTime = System.nanoTime(); uuid.parallelStream().sorted().collect(Collectors.toList()); parallelEndTime = System.nanoTime(); long millis = TimeUnit.NANOSECONDS.toMillis(parallelEndTime - startTime); System.out.println(“多线程” + millis); } @Test public void testErgodicString() { List<String> list = Arrays.asList(“Kirito”, “Asuna”, “Illyasviel”, “Sakura”); // 需求: 将数组中每个元素各个字母大写 并放入集合 System.out.println("——————–串行流stream———————"); // spliterator 分割迭代器 // 串行流stream() 单线程处理 / * default Stream<E> stream() { * return StreamSupport.stream(spliterator(), false);} / // List<String> collect = list.stream().map(str -> str.toUpperCase()).collect(Collectors.toList()); // R apply(T t); toUpperCase() 没有参数作为输入 // 但把调用toUpperCase的对象作为T作为输入 返回的R是return的对象结果 // List<String> collect = list.stream().map(String::toUpperCase).collect(Collectors.toList()); Function<String, String> function = String::toUpperCase; //等价于 (String str) -> str.toUpperCase() //方法引用 类的类型::实例方法 对应的lambda表达式 第一个输入参数 是调用此方法的对象 List<String> collect = list.stream().map(function).collect(Collectors.toList()); collect.forEach(System.out::println); this.testNormal(); System.out.println("—————–并行流parallelStream——————"); // 并行流parallelStream() 多线程处理 / * default Stream<E> parallelStream() { * return StreamSupport.stream(spliterator(), true);} */ List<String> parallelCollect = list.parallelStream().map(str -> str.toUpperCase()).collect(Collectors.toList()); parallelCollect.forEach(System.out::println); this.testParallel(); }} . ____ _ __ _ _ /\ / ’ __ _ () __ __ _ \ \ \ ( ( )__ | ‘_ | ‘| | ‘ / ` | \ \ \ \ \/ )| |)| | | | | || (| | ) ) ) ) ’ || .__|| ||| |_, | / / / / =========||==============|/=//// :: Spring Boot :: (v2.1.2.RELEASE)2019-02-20 15:54:54.321 INFO 7356 — [ main] c.j.design.java8.Stream.ErgodicString : Starting ErgodicString on DESKTOP-87RMBG4 with PID 7356 (started by 46250 in E:\IdeaProjects\design)2019-02-20 15:54:54.323 INFO 7356 — [ main] c.j.design.java8.Stream.ErgodicString : No active profile set, falling back to default profiles: default2019-02-20 15:54:54.817 INFO 7356 — [ main] c.j.design.java8.Stream.ErgodicString : Started ErgodicString in 0.705 seconds (JVM running for 1.528)——————–串行流stream———————KIRITOASUNAILLYASVIELSAKURA单线程10590—————–并行流parallelStream——————KIRITOASUNAILLYASVIELSAKURA多线程3313 ...

February 20, 2019 · 7 min · jiezi

pandas指南:做更高效的数据科学家

摘要:Python是开源的,所以有很多开源固有的问题。如果你是Python新手,很难知道针对特定任务的包哪个是最好的。你需要有经验的人来告诉你。今天我要告诉你们的是:在数据科学中,有一个软件包是你们绝对需要学习的,那就是pandas。而pandas真正有趣的地方是,很多其他的包也在里面。pandas是一个核心包,因此它具有来自其他各种包的特性。pandas类似于Python中的Excel:它使用表(即DataFrame)并对数据进行转换,但它还能做更多。如果你已经熟悉Python,可以直接进入第三部分现在让我们开始:import pandas as pdpandas包最基本的功能1、读取数据:data = pd.read_csv(‘my_file.csv’)data=pd.read_csv(‘my_file.csv’,sep=’;’,encoding=‘latin-1’,nrows=1000, kiprows=[2,5])sep变量代表分隔符。因为Excel中的csv分隔符是“;”,因此需要显示它。编码设置为“latin-1”以读取法语字符。nrows=1000表示读取前1000行。skiprows=[2,5]表示在读取文件时将删除第2行和第5行最常用的函数:read_csv, read_excel还有一些很不错的函数:read_clipboard、read_sql2、写入数据data.to_csv(‘my_new_file.csv’, index=None)index=None将简单地按原样写入数据。如果你不写index=None,会得到额外的行。我通常不使用其他函数,比如to_excel,to_json,to_pickle,to_csv,虽然它们也做得很好,但是csv是保存表最常用的方法。3、检查数据:data.shapedata.describe()data.head(3).head(3)打印数据的前3行,.tail()函数将查看数据的最后一行。data.loc[8]打印第8行。data.loc[8, ‘column_1’]将第8行值打印在“column_1”上。data.loc[range(4,6)]打印第4行到第6行。pandas的初级功能1、逻辑运算data[data[‘column_1’]==‘french’]data[(data[‘column_1’]==‘french’) & (data[‘year_born’]==1990)]data[(data[‘column_1’]==‘french’)&(data[‘year_born’]==1990)&(data[‘city’]==‘London’)]如果要根据逻辑操作对数据进行运算,在使用& (AND)、~ (NOT)和| (OR)等逻辑操作之前和之后添加“(”&“)”。data[data[‘column_1’].isin([‘french’, ’english’])]不要为同一列编写多个OR,最好是使用.isin()函数。2、基本绘图多亏了matplotlib包,这个特性才得以实现。就像我们在介绍中说的,它可以直接用在pandas身上。data[‘column_numerical’].plot()data[‘column_numerical’].hist()绘制分布图(直方图)%matplotlib inline如果你使用Jupyter,在绘图之前,不要忘记写这一行(在代码中只写一次)3、更新数据data.loc[8, ‘column_1’] = ’english’将’ column_1 ‘的第8行值替换为’ english ‘data.loc[data[‘column_1’]==‘french’, ‘column_1’] = ‘French’在一行中更改多行值pandas的中级功能现在你可以做一些在Excel中很容易做的事情。让我们来挖掘一些在Excel中做不到的神奇事情。1、计算功能data[‘column_1’].value_counts()2、对全行、全列或所有数据的操作data[‘column_1’].map(len)len()函数应用于“column_1”的每个元素map()操作将一个函数应用于列的每个元素。data[‘column_1’].map(len).map(lambda x : x/100).plot()pandas的另一个特点是进行链式操作。它可以帮助你在一行代码中执行多个操作,从而更加简单和高效。data.apply(sum).apply()将函数应用于列。.applymap()将一个函数应用于表(DataFrame)中的所有单元格。3、tqdm包在处理大型数据集时,pandas可能需要一些时间来运行.map()、.apply()、.applymap()操作。tqdm是一个非常有用的包,它可以帮助预测这些操作何时完成。from tqdm import tqdm_notebooktqdm_notebook().pandas()用pandas设置tqdmdata[‘column_1’].progress_map(lambda x : x.count(’e’))将.map()替换为.progress_map(),.apply()和.applymap()也是一样4、相关矩阵和散射矩阵data.corr()data.corr().applymap(lambda x : int(x*100)/100)pd.plotting.scatter_matrix(data, figsize=(12,8))pandas的高级功能1、行列合并在pandas中,行列合并非常简单。data.merge(other_data, on=[‘column_1’, ‘column_2’, ‘column_3’])合并3列只需要一行代码2、分组分组一开始并不简单,但是如果掌握其语法,你将发现这非常简单。data.groupby(‘column_1’)[‘column_2’].apply(sum).reset_index()按列分组,选择要在其上操作函数的另一列。reset_index()将数据重新生成DataFrame(表)3、遍历行dictionary = {}for i,row in data.iterrows():dictionary[row[‘column_1’]] = row[‘column_2’]iterrows()循环两个变量:行索引和行(上面代码中的i和row)。总体来说,pandas是一个帮助数据科学家快速阅读和理解数据的工具包,它也可以说是Python如此优秀的原因之一。我还可以展示更多pandas包其他有趣的特点,但以上所述足以让人理解为什么数据科学家离不开pandas包。总之,pandas包有以下特点:1、 简单易用,隐藏了所有复杂和抽象的计算;2、非常直观;3、快速。本文作者:【方向】阅读原文本文为云栖社区原创内容,未经允许不得转载。

January 25, 2019 · 1 min · jiezi