问题

现有社保卡和身份证若干,想要匹配筛选出一一对应的社保卡和身份证。

转换为List<社保卡> socialList,和List idList,从二者中找出匹配的社保卡。

模型

创建社保卡类

/**
* @author Ryan Miao
*/
class SocialSecurity{
private Integer id;//社保号码
private Integer idCard;//身份证号码
private String somethingElse; public SocialSecurity(Integer id, Integer idCard, String somethingElse) {
this.id = id;
this.idCard = idCard;
this.somethingElse = somethingElse;
} public Integer getId() {
return id;
} public Integer getIdCard() {
return idCard;
} public String getSomethingElse() {
return somethingElse;
} @Override
public String toString() {
return "SocialSecurity{" +
"id=" + id +
", idCard=" + idCard +
", somethingElse='" + somethingElse + '\'' +
'}';
}
}

创建身份证类

class IdCard {
private Integer id;//身份证号码
private String somethingElse; public IdCard(Integer id, String somethingElse) {
this.id = id;
this.somethingElse = somethingElse;
} public Integer getId() {
return id;
} public String getSomethingElse() {
return somethingElse;
} @Override
public String toString() {
return "IdCard{" +
"id=" + id +
", somethingElse='" + somethingElse + '\'' +
'}';
}
}

最简单的办法:遍历

只要做两轮循环即可。

准备初始化数据:



private ArrayList<SocialSecurity> socialSecurities;
private ArrayList<IdCard> idCards; @Before
public void setUp(){
socialSecurities = Lists.newArrayList(
new SocialSecurity(1, 12, "小明"),
new SocialSecurity(2, 13, "小红"),
new SocialSecurity(3, 14, "小王"),
new SocialSecurity(4, 15, "小peng")
); idCards = Lists.newArrayList(
new IdCard(14, "xiaopeng"),
new IdCard(13, "xiaohong"),
new IdCard(12, "xiaoming")
); //目标: 从socialSecurities中筛选出idCards中存在的卡片
}

遍历

 @Test
public void testFilterForEach(){
List<SocialSecurity> result = new ArrayList<>();
int count = 0;
for (SocialSecurity socialSecurity : socialSecurities) {
for (IdCard idCard : idCards) {
count++;
if (socialSecurity.getIdCard().equals(idCard.getId())){
result.add(socialSecurity);
}
}
} System.out.println(result);
System.out.println(count);//12 = 3 * 4
//O(m,n) = m*n;
}

很容易看出,时间复杂度O(m,n)=m*n.

采用Hash

通过观察发现,两个list取相同的部分时,每次都遍历两个list。那么,可以把判断条件放入Hash中,判断hash是否存在来代替遍历查找。

@Test
public void testFilterHash(){
Set<Integer> ids = idCards
.stream()
.map(IdCard::getId)
.collect(Collectors.toSet());
List<SocialSecurity> result = socialSecurities
.stream()
.filter(e->ids.contains(e.getIdCard()))
.collect(Collectors.toList()); System.out.println(result);
//初始化 hash 3
//遍历socialSecurities 4
//从hash中判断key是否存在 4
//O(m,n)=2m+n=11
}

如此,假设hash算法特别好,hash的时间复杂度为O(n)=n。如此推出这种做法的时间复杂度为O(m,n)=2m+n. 当然,更重要的是这种写法更让人喜欢,天然不喜欢嵌套的判断,喜欢扁平化的风格。

Hash一定会比遍历快吗

想当然的以为,hash肯定会比遍历快,因为是hash啊。其实,可以算算比较结果。比较什么时候2m+n < m*n

从数据归纳法的角度,n必须大于2,不然即演变程2m+2 < 2m。于是,当n>2时:

@Test
public void testCondition(){
int maxN = 0;
for (int m = 2; m < 100; m++) {
for (int n = 3; n < 100; n++) {
if ((2*m+n)>m*n){
System.out.println("m="+m +",n="+n);
if (n>maxN){
maxN = n;
}
}
}
} System.out.println(maxN);
}

结果是:

m=2,n=3
3

也就是说n<=3的时候,遍历要比hash快。事实上还要更快,因为hash还需要创建更多的对象。然而,大部分情况下,n也就是第二个数组的长度是大于3的。这就是为什么说hash要更好写。当然,另一个很重要的原因是lambda stream的运算符号远比嵌套循环让人喜爱。

如何从两个List中筛选出相同的值的更多相关文章

  1. js下拉框:从数组中筛选出匹配的数据

    handleChange(val) { let obj = {} // 遍历数组 obj = this.options.find(item => { // 筛选出匹配的数据 return ite ...

  2. 【java小工具】从.java文件中筛选出方法,并计算出方法在这些文件中出现的次数

    package getMethod; import java.io.*; import java.util.*; import java.util.regex.Matcher; import java ...

  3. 使用pandas筛选出指定列值所对应的行

    在pandas中怎么样实现类似mysql查找语句的功能: select * from table where column_name = some_value; pandas中获取数据的有以下几种方法 ...

  4. 选取两个有序数组中最大的K个值,降序存入另一个数组中

    原题: 假设有两个有序的整型数组int *a1, int *a2,长度分别为m和n.试用C语言写出一个函数选取两个数组中最大的K个值(K可能大于m+n)写到int *a3中,保持a3降序,并返回a3实 ...

  5. Leetcode33--->Search in Rotated Sorted Array(在旋转数组中找出给定的target值的位置)

    题目: 给定一个旋转数组,但是你不知道旋转位置,在旋转数组中找出给定target值出现的位置:你可以假设在数组中没有重复值出现 举例: (i.e., 0 1 2 4 5 6 7 might becom ...

  6. JS函数 编程练习 使用javascript代码写出一个函数:实现传入两个整数后弹出较大的整数。

    编程练习 使用javascript代码写出一个函数:实现传入两个整数后弹出较大的整数. 任务 第一步: 编写代码完成一个函数的定义吧. 第二步: 我们来补充函数体中的控制语句,完成函数功能吧. 提示: ...

  7. 键相同,比较两个map中的值是否相同

    获取.排序.比较两个Map中相同key对应value值 /** * * @param hashMap 原数据 * @param hashMap2 需要比较的数据 * @return */ privat ...

  8. 【452】pandas筛选出表中满足另一个表所有条件的数据

    参考:pandas筛选出表中满足另一个表所有条件的数据 参考:pandas:匹配两个dataframe 使用 pd.merge 来实现 on 表示查询的 columns,如果都有 id,那么这是很好的 ...

  9. Java - Collection 高效的找出两个List中的不同元素

    如题:有List<String> list1和List<String> list2,两个集合各有上万个元素,怎样取出两个集合中不同的元素? 方法1:遍历两个集合 public ...

随机推荐

  1. js 移动端识别手机号码

    需求: 在移动端一个页面内多处有数字显示,其中希望能够自动识别我所要求的那个手机号码,点击可以拨打 探索: 首先想到的是头部的meta标签<meta name="format-dete ...

  2. 高新技术---枚举及部分JDK1.5新特性

    第一讲     枚举 一.概述 这里说的枚举,不是集合vector的特有枚举迭代器,而是JDK1.5的一个新特性.之所以单独拿它开刷,是这个知识点比较重要,同时相对来说比较难理解一些. 为什么要有枚举 ...

  3. javascript实现jsp页面的打印预览

    1.加载WebBrowser打印预览控件 <OBJECT classid="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2" heigh ...

  4. JS面向对象编程(进阶理解)

    JS 面向对象编程 如何创建JS对象 JSON语法声明对象(直接量声明对象) var obj = {}; 使用 Object 创建对象 var obj = new Object(); JS对象可以后期 ...

  5. 创建DNS子域及view

    author:JevonWei 版权声明:原创作品 子域 子域同父域在同一个服务器上 新建子域jevon.danran.com vim /etc/named.rfc1912.zones zone &q ...

  6. Spring定时任务quartz表达式

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp32 0 0 12 * * ?---------------在每天中午12: ...

  7. Linux修改文件permission属性

    列出文件属性 ls -al 修改文件属性为可读.可写 sudo chmod -c 777 <your file name>

  8. grunt之watch续

    上一回没有说完,我就是这样,做之前心中波澜壮阔,锦绣山河,等画完小草开始烦躁,完成鲜花出现动摇,然后心神涣散,最后虎头蛇尾. 现在弥补下之前遗漏的问题. watch(V0.6.1)的tasks和opt ...

  9. Spring Ioc DI 原理

    IOC(DI):其实这个Spring架构核心的概念没有这么复杂,更不像有些书上描述的那样晦涩.Java程序员都知道:java程序中的每个业务逻辑至少需要两个或以上的对象来协作完成,通常,每个对象在使用 ...

  10. 201521123035《Java程序设计》第四周学习总结

    本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 本周还讲了注释与类设计.老师用例子向我们展示实际生活中一个类里面包含了哪些属性,并由此联想到如果自 ...