日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
類比C#、JavaScript和Java的集合數(shù)據(jù)處理

Java 丟了好多年,最近在揀起來(lái),首先當(dāng)然是了解這么多年來(lái)它的變化,于是發(fā)現(xiàn)了 Java 8 的java.util.stream。在學(xué)習(xí)和試驗(yàn)的過(guò)程中,相比較于 C# 和 javascript,有那么些心得,作文以記之。

創(chuàng)新互聯(lián)是專業(yè)的橫山網(wǎng)站建設(shè)公司,橫山接單;提供網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì),網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行橫山網(wǎng)站開(kāi)發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!

早些時(shí)間寫(xiě)過(guò)一篇《ES6 的 for..of 和 Generator,從偽數(shù)組 jQuery 對(duì)象說(shuō)起》,和這個(gè)主題有點(diǎn)關(guān)系。其實(shí)我記得還有一篇講 C# 的,沒(méi)找到,也許只是想過(guò),沒(méi)寫(xiě)成,成了虛假記憶。

前言

之所以把 C#、JavaScript 和 Java 三種語(yǔ)言的實(shí)現(xiàn)寫(xiě)在一起,主要是為了放在一起有一個(gè)類比,可能會(huì)有助于理解。

集合數(shù)據(jù)

C# 的集合數(shù)據(jù)基類是 Collection,它實(shí)現(xiàn)了 ICollection接口,而 ICollection 又從 IEnumerable 接口繼承——實(shí)際上要討論的內(nèi)容都基于 IEnumerable 接口。另外還有一個(gè)非泛型的 IEnumerable 接口,不過(guò)建議大家盡量使用泛型,所以這個(gè)非泛型的接口就當(dāng)我沒(méi)說(shuō)。順便提一句,數(shù)組也是實(shí)現(xiàn)了 IEnumerable 接口的。System.Linq 中提供的擴(kuò)展大大方便了集合處理過(guò)程。

JavaScript 最常見(jiàn)的集合數(shù)據(jù)類型就是數(shù)組,自 ES6 發(fā)布以后,這個(gè)范圍擴(kuò)展到了 iterable 對(duì)象。不過(guò)這里要討論的內(nèi)容都是在Array.prototype 中實(shí)現(xiàn)的。除此之外,underscore、lodash 這些第三方庫(kù)中也實(shí)現(xiàn)了很多集合數(shù)據(jù)處理的方法,但不在本文討論內(nèi)容之內(nèi)。

Java 的集合類型由 Collection 接口定義。本文討論的內(nèi)容是 Java 8 的特性,在 java.util.stream 包中實(shí)現(xiàn),由Collection.stream() 引入。

示例語(yǔ)言版本

  • 后面示例中的部分 C# 語(yǔ)句可能需要支持 6.0 語(yǔ)言版本的編譯器,如 Visual Studio 2015 或者 Visual Studio "15"
  • JavaScript 代碼都使用了 ES6 語(yǔ)法,目前大部分瀏覽器支持,Node 5 也完全支持。
  • Java 要求 Java 8(或 1.8)版本

遍歷

問(wèn)題提出

給定一個(gè)名稱列表,數(shù)組類型, ["Andy", "Jackson", "Yoo"],要求遍歷出到的控制臺(tái)。

C# 的遍歷

對(duì)于集合來(lái)說(shuō),最常用的就是遍歷,不過(guò) for,foreach, while 之類大家都耳熟能詳了,不再多說(shuō)。這里說(shuō)的是 forEach() 方法。

很遺憾,C# 的 Linq 擴(kuò)展 里沒(méi)有提供 ForEach() 方法,不過(guò) All(IEnumerable, Func) 和 Any(IEnumerable, Func) 都可以代替。這兩個(gè)方法的區(qū)別就在于第二個(gè)參數(shù) Func 的返回值。這兩個(gè)方法都會(huì)遍歷集合,對(duì)集合中的每個(gè)元素依次調(diào)用第二個(gè)參數(shù),F(xiàn)unc 所指的委托方法,并檢查其返回值,All() 檢查到 false 中止遍歷,而Any() 檢查到 true 中止遍歷。

All() 的意思是,所有元素都符合條件則返回 true,所有只要有一個(gè)不符合條件,返回了 false,則中止遍歷,返回false;Any() 的意思是只要發(fā)現(xiàn)有元素符合條件則返回 true。

Func 是一個(gè)公用委托。Func<...> 系列公用委托都用于委托帶有返回值的的方法,所有 Func<..., TResult>都是***一個(gè)參數(shù) TResult 代表返回值類型。

因此,C# 的遍歷輸出可以這樣實(shí)現(xiàn)

 
 
  1. string[] names = { "Andy", "Jackson", "Yoo" }; 
  2. names.All(name => { 
  3.     Console.WriteLine(name); 
  4.     return true; 
  5. });  
 
 
  1. string[] names = { "Andy", "Jackson", "Yoo" }; 
  2. names.Any(name => { 
  3.     Console.WriteLine(name); 
  4.     return false; 
  5. });  

有 Lambda 就是好

JavaScript 的遍歷

JavaScript 的 Array 實(shí)現(xiàn)了 forEach 實(shí)例方法,即 Array.prototype.forEach()。

對(duì)于 JavaScript 的數(shù)組,可以這樣遍歷

 
 
  1. var names = ["Andy", "Jackson", "Yoo"]; 
  2. names.forEach(name => { 
  3.     console.log(name); 
  4. });  

對(duì)于 JavaScript 的偽數(shù)組,可以這樣

 
 
  1. var names = { 
  2.     0: "Andy", 
  3.     1: "Jackson", 
  4.     2: "Yoo", 
  5.     length: 3 
  6. }; 
  7.  
  8. [].forEach.call(names, name => { 
  9.     console.log(name); 
  10. });  

jQuery 的遍歷

jQuery 是一個(gè)常用的 JavaScript 庫(kù),它封裝的對(duì)象都是基于偽數(shù)組的,所以 jQuery 中經(jīng)常用到遍歷。除了網(wǎng)頁(yè)元素集合外,jQuery 也可以遍歷普通數(shù)組,有兩種方式

可以直接把數(shù)組作為***個(gè)參數(shù),處理函數(shù)作為第二個(gè)參數(shù)調(diào)用 $.each()。

 
 
  1. const names = ["Andy", "Jackson", "Yoo"]; 
  2. $.each(names, (i, name) => { 
  3.     console.log(name); 
  4. }); 

也可以把數(shù)組封裝成一個(gè) jQuery 對(duì)象($(names)),再在這個(gè) jQuery 對(duì)象上調(diào)用 eash() 方法。

 
 
  1. const names = ["Andy", "Jackson", "Yoo"]; 
  2. $(names).each((i, name) => { 
  3.     console.log(name); 
  4. });  

兩種方法的處理函數(shù)都一樣,但是要注意,這和原生 forEach() 的處理函數(shù)有點(diǎn)不同。jQuery 的 each() 處理函數(shù),***個(gè)參數(shù)是序號(hào),第二個(gè)參數(shù)是數(shù)組元素;而原生 forEach() 的處理函數(shù)正好相反,***個(gè)參數(shù)是數(shù)組元素,第二個(gè)參數(shù)才是序號(hào)。

另外,$.each() 對(duì)偽數(shù)組同樣適用,不需要通過(guò) call() 來(lái)調(diào)用。

Java 的遍歷

 
 
  1. String[] names = { "Andy", "Jackson", "Yoo" }; 
  2. List list = Arrays.asList(names); 
  3. list.forEach(name -> { 
  4.     System.out.println(name); 
  5. });  

過(guò)濾(篩選)數(shù)據(jù)

問(wèn)題提出

給出一組整數(shù),需要將其中能被 3 整除選出來(lái) 

 
 
  1. [46, 74, 20, 37, 98, 93, 98, 48, 33, 15] 

期望結(jié)果

 
 
  1. [93, 48, 33, 15] 

C# 中過(guò)濾使用 Where() 擴(kuò)展

 
 
  1. int[] data = { 46, 74, 20, 37, 98, 93, 98, 48, 33, 15 }; 
  2. int[] result = data.Where(n => n % 3 == 0).ToArray();  

注意:Where() 的結(jié)果即不是數(shù)組也不是 List,需要通過(guò) ToArray() 生成數(shù)組,或者通過(guò) ToList() 生成列表。Linq 要在ToArray() 或者 ToList() 或者其它某些操作的時(shí)候才會(huì)真正遍歷,依次執(zhí)行 Where() 參數(shù)提供的那個(gè)篩選函數(shù)。

JavaScript 中有 Array.prototype.filter

 
 
  1. const data = [46, 74, 20, 37, 98, 93, 98, 48, 33, 15]; 
  2. const result = data.filter(n => { 
  3.     return n % 3 === 0; 
  4. });  

Java 中使用到 java.util.stream.*

Java 中可以通過(guò) java.util.stream.IntStream.of() 來(lái)從數(shù)組生成 stream 對(duì)象

 
 
  1. final int[] data = { 46, 74, 20, 37, 98, 93, 98, 48, 33, 15 }; 
  2. int[] result = IntStream.of(data) 
  3.         .filter(n -> n % 3 == 0) 
  4.         .toArray();  

需要注意的是,Arrays.asList(data).stream() 看起來(lái)也可以生成 stream 對(duì)象,但是通過(guò)調(diào)試會(huì)發(fā)現(xiàn),這是一個(gè) Stream而不是 Stream。原因是 asList(T ...a) 其參數(shù)可變參數(shù),而且要求參數(shù)類型是類,所以 asList(data) 是把 data 作為一個(gè) int[] 類型參數(shù)而不是 int 類型的參數(shù)數(shù)據(jù)。如果要從 int[] 生成 List,還得通過(guò) IntStream 來(lái)處理

 
 
  1. List list = IntStream.of(data) 
  2.         .boxed() 
  3.         .collect(Collectors.toList());  

映射處理

映射處理是指將某種類型的集合,將其元素依次映射成另一種類型,產(chǎn)生一個(gè)新類型的集合。新集合中的每個(gè)元素都與原集中的同樣位置的元素有對(duì)應(yīng)關(guān)系。

問(wèn)題提出

這里提出一個(gè)精典的問(wèn)題:成績(jī)轉(zhuǎn)等級(jí),不過(guò)為了簡(jiǎn)化代碼(switch 或多重 if 語(yǔ)句代碼比較長(zhǎng)),改為判斷成績(jī)是否及格,60 分為及格線。

偷個(gè)懶,就用上個(gè)問(wèn)題的輸入 [46, 74, 20, 37, 98, 93, 98, 48, 33, 15],

期望結(jié)果:

 
 
  1. ["REJECT","PASS","REJECT","REJECT","PASS","PASS","PASS","REJECT","REJECT","REJECT"] 

C# 通過(guò) Select() 來(lái)進(jìn)行映射處理。

 
 
  1. int[] scores = { 46, 74, 20, 37, 98, 93, 98, 48, 33, 15 }; 
  2. string[] levels = scores 
  3.     .Select(score => score >= 60 ? "PASS" : "REJECT") 
  4.     .ToArray();  

JavaScript 通過(guò) Array.prototype.map 來(lái)進(jìn)行映射處理。

 
 
  1. const scores = [46, 74, 20, 37, 98, 93, 98, 48, 33, 15]; 
  2. const levels = scores.map(score => { 
  3.     return score >= 60 ? "PASS" : "REJECT"; 
  4. });  

Java 的 Stream 提供了 mapToObj() 等方法處理映射

 
 
  1. final int[] scores = { 46, 74, 20, 37, 98, 93, 98, 48, 33, 15 }; 
  2. String[] levels = IntStream.of(scores) 
  3.         .mapToObj(score -> score >= 60 ? "PASS" : "REJECT") 
  4.         .toArray(String[]::new);  

與“篩選”示例不同,在“篩選”示例中,由于篩選結(jié)果是 IntStream,可以直接調(diào)用 InStream::toArray() 來(lái)得到 int[]。

但在這個(gè)示例中,mapToObj() 得到的是一個(gè) Stream,類型擦除后就是 Stream,所以 Stream::toArray() 默認(rèn)得到的是一個(gè) Object[] 而不是 String[]。如果想得到 String[],需要為 toArray() 指定 String[] 的構(gòu)造函數(shù),即 String[]::new。

生成查找表(如哈希表)

查找表在數(shù)據(jù)結(jié)構(gòu)里的意義還是比較寬的,其中通過(guò)哈希算法實(shí)現(xiàn)的稱為哈希表。C# 中通常是用 Directory,不過(guò)它是不是通過(guò)哈希實(shí)現(xiàn)我就不清楚了。不過(guò) Java 中的 HashMap 和 Hashtable,從名稱就看得出來(lái)是實(shí)現(xiàn)。JavaScript 的字面對(duì)象據(jù)稱也是哈希實(shí)現(xiàn)。

提出問(wèn)題

現(xiàn)在有一個(gè)姓名列表,是按學(xué)號(hào)從 1~7 排列的,需要建立一個(gè)查找到,使之能通過(guò)姓名很容易找到對(duì)應(yīng)的學(xué)號(hào)。

 
 
  1. ["Andy", "Jackson", "Yoo", "Rose", "Lena", "James", "Stephen"] 

期望結(jié)果

 
 
  1. Andy    => 1 
  2. Jackson => 2 
  3. Yoo     => 3 
  4. Rose    => 4 
  5. Lena    => 5 
  6. James   => 6 
  7. Stephen => 7    

C# 使用 ToDictionary()

 
 
  1. string[] names = { "Andy", "Jackson", "Yoo", "Rose", "Lena", "James", "Stephen" }; 
  2. int i = 1; 
  3. Dictionary map = names.ToDictionary(n => n, n => i++);  

C# Linq 擴(kuò)展提供的若干方法都沒(méi)有將序號(hào)傳遞給處理函數(shù),所以上例中采用了臨時(shí)變量計(jì)數(shù)的方式來(lái)進(jìn)行。不過(guò)有一個(gè)看起來(lái)好看一點(diǎn)的辦法,用 Enumerable.Range() 先生成一個(gè)序號(hào)的序列,再基于這個(gè)序列來(lái)處理

 
 
  1. string[] names = { "Andy", "Jackson", "Yoo", "Rose", "Lena", "James", "Stephen" }; 
  2. IEnumerable indexes = Enumerable.Range(0, names.Length); 
  3. Dictionary map = indexes.ToDictionary(i => names[i], i => i + 1);  

JavaScript 的兩種處理辦法

JavaScript 沒(méi)有提供從 [] 到 {} 的轉(zhuǎn)換函數(shù),不過(guò)要做這個(gè)轉(zhuǎn)換也不是好麻煩,用 forEach 遍歷即可

 
 
  1. var map = (function() { 
  2.     var m = {}; 
  3.     names.forEach((name, i) => { 
  4.         m[name] = i + 1; 
  5.     }); 
  6.     return m; 
  7. })();  

為了不讓臨時(shí)變量污染外面的作用域,上面的示例中采用了 IEFE 的寫(xiě)法。不過(guò),如果用 Array.prototype.reduce 則可以讓代碼更簡(jiǎn)潔一些

 
 
  1. var map = names.reduce((m, name, i) => { 
  2.     m[name]  = i + 1; 
  3.     return m; 
  4. }, {});  

Java 的 Collectors

Java 的處理函數(shù)也沒(méi)有傳入序號(hào),所以在 Java 中的實(shí)例和 C# 類似。不過(guò),***種方法不可用,因?yàn)?Java Lambda 的實(shí)現(xiàn)相當(dāng)于是匿名類對(duì)接口的實(shí)現(xiàn),只能訪問(wèn)局部的 final 變量,i 要執(zhí)行 i++ 操作,顯然不是 final 的,所以只能用第二種辦法

 
 
  1. final String[] names = { "Andy", "Jackson", "Yoo", "Rose", "Lena", "James", "Stephen" }; 
  2. Map map = IntStream.range(0, names.length) 
  3.     .boxed() 
  4.     .collect(Collectors.toMap(i -> names[i], i -> i + 1));  

我只能說(shuō) .boxed() 是個(gè)大坑啊,一定要記得調(diào)。

匯總和聚合處理

匯總處理就是合計(jì)啊,平均數(shù)啊之類的,使用方式都差不多,所以以合計(jì)(Sum)為例。

匯總處理其實(shí)是聚合處理的一個(gè)特例,所以就同一個(gè)問(wèn)題,再用普通的聚合處理方式再實(shí)現(xiàn)一次。

問(wèn)題提出

已知全班成績(jī),求班總分,再次用到了那個(gè)數(shù)組

 
 
  1. [46, 74, 20, 37, 98, 93, 98, 48, 33, 15] 

期望結(jié)果:562

C# 的實(shí)現(xiàn)

C# 可以直接使用 Sum() 方法求和

 
 
  1. int[] scores = { 46, 74, 20, 37, 98, 93, 98, 48, 33, 15 }; 
  2. int sum = scores.Sum();  

聚合實(shí)現(xiàn)方式(用 Aggregate())

 
 
  1. int[] scores = { 46, 74, 20, 37, 98, 93, 98, 48, 33, 15 }; 
  2. int sum = scores.Aggregate(0, (total, score) => { 
  3.     return total + score; 
  4. });  

聚合實(shí)現(xiàn)方式要靈活得多,比如,改成乘法就可以算階乘。當(dāng)然用于其它更復(fù)雜的情況也不在話下。前面生成查找表的 JavaScript 部分就是采用聚合來(lái)實(shí)現(xiàn)的。

JavaScript 都是通過(guò)聚合來(lái)實(shí)現(xiàn)的

 
 
  1. const scores = [46, 74, 20, 37, 98, 93, 98, 48, 33, 15]; 
  2. const sum = scores.reduce((total, score) => { 
  3.     return total + score; 
  4. }, 0);  

注意 C# 的初始值在前,JavaScript 的初始值在后,這是有區(qū)別的。參數(shù)順序嘛,注意一下就行了。

Java 中使用 Stream::reduce 進(jìn)行聚合處理

IntStream 提供了 sum() 方法

 
 
  1. final int[] scores = { 46, 74, 20, 37, 98, 93, 98, 48, 33, 15 }; 
  2. final int sum = IntStream.of(scores).sum();  

同樣也可以用 reduce 處理

 
 
  1. final int[] scores = { 46, 74, 20, 37, 98, 93, 98, 48, 33, 15 }; 
  2. final int sum = IntStream.of(scores) 
  3.         .reduce(0, (total, score) -> total + score);  

綜合應(yīng)用

問(wèn)題提出

已知全班 7 個(gè)人,按學(xué)號(hào) 從 1~7 分別是 

 
 
  1. ["Andy", "Jackson", "Yoo", "Rose", "Lena", "James", "Stephen"] 

這 7 個(gè)人的成績(jī)按學(xué)號(hào)序,分別是

 
 
  1. [66, 74, 43, 93, 98, 88, 83] 

有 Student 數(shù)組結(jié)構(gòu)

 
 
  1. Student { 
  2.     number: int 
  3.     name: string 
  4.     score: int 
  5. }  

要求得到全班 7 人的 student 數(shù)組,且該數(shù)組按分?jǐn)?shù)從高到低排序

C# 實(shí)現(xiàn)

 
 
  1. sealed class Student { 
  2.     public int Number { get; } 
  3.     public string Name { get; } 
  4.     public int Score { get; } 
  5.      
  6.     public Student(int number, string name, int score) { 
  7.         Number = number; 
  8.         Name = name; 
  9.         Score = score; 
  10.     } 
  11.      
  12.     public override string ToString() => $"[{Number}] {Name} : {Score}"; 
  13. Student[] students = Enumerable.Range(0, names.Length) 
  14.     .Select(i => new Student(i + 1, names[i], scores[i])) 
  15.     .OrderByDescending(s => s.Score) 
  16.     .ToArray();  

注意 C# 中排序有 OrderBy 和 OrderByDescending 兩個(gè)方法,一般情況下只需要給一個(gè)映射函數(shù),從原數(shù)據(jù)里找到要用于比較的數(shù)據(jù)即可使用其 >、< 等運(yùn)算符進(jìn)行比較。如果比例起來(lái)比較復(fù)雜的,需要提供第二個(gè)參數(shù),一個(gè) IComparer 的實(shí)現(xiàn)

JavaScript 實(shí)現(xiàn)

 
 
  1.  constructor(number, name, score) { 
  2.         this._number = number; 
  3.         this._name = name; 
  4.         this._score = score; 
  5.     } 
  6.  
  7.     get number() { 
  8.         return this._number; 
  9.     } 
  10.  
  11.     get name() { 
  12.         return this._name; 
  13.     } 
  14.  
  15.     get score() { 
  16.         return this._score; 
  17.     } 
  18.  
  19.     toString() { 
  20.         return `[${this.number}] ${this.name} : ${this.score}`; 
  21.     } 
  22. const names = ["Andy", "Jackson", "Yoo", "Rose", "Lena", "James", "Stephen"]; 
  23. const scores = [66, 74, 43, 93, 98, 88, 83]; 
  24.  
  25. var students = names 
  26.     .map((name, i) => new Student(i + 1, name, scores[i])) 
  27.     .sort((a, b) => { 
  28.         return b.score - a.score; 
  29.     }); 

 JavaScript 的排序則是直接給個(gè)比較函數(shù),根據(jù)返回的數(shù)值小于0、等于0或大于0來(lái)判斷是小于、等于還是大于。

Java 實(shí)現(xiàn) 

 
 
  1. final class Student { 
  2.     private int number; 
  3.     private String name; 
  4.     private int score; 
  5.  
  6.     public Student(int number, String name, int score) { 
  7.         this.number = number; 
  8.         this.name = name; 
  9.         this.score = score; 
  10.     } 
  11.  
  12.     public int getNumber() { 
  13.         return number; 
  14.     } 
  15.  
  16.     public String getName() { 
  17.         return name; 
  18.     } 
  19.  
  20.     public int getScore() { 
  21.         return score; 
  22.     } 
  23.  
  24.     @Override 
  25.     public String toString() { 
  26.         return String.format("[%d] %s : %d", getNumber(), getName(), getScore()); 
  27.     } 
  28. final String[] names = { "Andy", "Jackson", "Yoo", "Rose", "Lena", "James", "Stephen" }; 
  29. final int[] scores = { 66, 74, 43, 93, 98, 88, 83 }; 
  30. Student[] students = IntStream.range(0, names.length) 
  31.         .mapToObj(i -> new Student(i + 1, names[i], scores[i])) 
  32.         .sorted((a, b) -> b.getScore() - a.getScore()) 
  33.         .toArray(Student[]::new);  

網(wǎng)站題目:類比C#、JavaScript和Java的集合數(shù)據(jù)處理
當(dāng)前路徑:http://m.5511xx.com/article/cdjepgo.html