現有社保卡和身份證若干,想要匹配篩選出一一對應的社保卡和身份證。
轉換爲List<社保卡> socialList,和List<IDcard> idList,從兩者中找出匹配的社保卡。java
建立社保卡類算法
/** * @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 + '\'' + '}'; } }
只要作兩輪循環便可。
準備初始化數據:ide
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中存在的卡片 }
遍歷this
@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.spa
經過觀察發現,兩個list取相同的部分時,每次都遍歷兩個list。那麼,能夠把判斷條件放入Hash中,判斷hash是否存在來代替遍歷查找。code
@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啊。其實,能夠算算比較結果。比較何時2m+n < m*n
。
從數據概括法的角度,n必須大於2,否則即演變程2m+2 < 2m
。因而,當n>2時:ci
@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); }
結果是:rem
m=2,n=3 3
也就是說n<=3的時候,遍歷要比hash快。事實上還要更快,由於hash還須要建立更多的對象。然而,大部分狀況下,n也就是第二個數組的長度是大於3的。這就是爲何說hash要更好寫。固然,另外一個很重要的緣由是lambda stream的運算符號遠比嵌套循環讓人喜好。