摘要:系列公用委托都用于委托帶有返回值的的方法,所有都是最后一個參數(shù)代表返回值類型。的字面對象據(jù)稱也是哈希實現(xiàn)。
前言Java 丟了好多年,最近在揀起來,首先當(dāng)然是了解這么多年來它的變化,于是發(fā)現(xiàn)了 Java 8 的java.util.stream。在學(xué)習(xí)和試驗的過程中,相比較于 C# 和 javascript,有那么些心得,作文以記之。
早些時間寫過一篇《ES6 的 for..of 和 Generator,從偽數(shù)組 jQuery 對象說起》,和這個主題有點關(guān)系。其實我記得還有一篇講 C# 的,沒找到,也許只是想過,沒寫成,成了虛假記憶。
之所以把 C#、JavaScript 和 Java 三種語言的實現(xiàn)寫在一起,主要是為了放在一起有一個類比,可能會有助于理解。
集合數(shù)據(jù)C# 的集合數(shù)據(jù)基類是 Collection
JavaScript 最常見的集合數(shù)據(jù)類型就是數(shù)組,自 ES6 發(fā)布以后,這個范圍擴(kuò)展到了 iterable 對象。不過這里要討論的內(nèi)容都是在 Array.prototype 中實現(xiàn)的。除此之外,underscore、lodash 這些第三方庫中也實現(xiàn)了很多集合數(shù)據(jù)處理的方法,但不在本文討論內(nèi)容之內(nèi)。
Java 的集合類型由 Collection
遍歷 問題提出后面示例中的部分 C# 語句可能需要支持 6.0 語言版本的編譯器,如 Visual Studio 2015 或者 Visual Studio "15"
JavaScript 代碼都使用了 ES6 語法,目前大部分瀏覽器支持,Node 5 也完全支持。
Java 要求 Java 8(或 1.8)版本
給定一個名稱列表,數(shù)組類型, ["Andy", "Jackson", "Yoo"],要求遍歷出到的控制臺。
C# 的遍歷對于集合來說,最常用的就是遍歷,不過 for,foreach, while 之類大家都耳熟能詳了,不再多說。這里說的是 forEach() 方法。
很遺憾,C# 的 Linq 擴(kuò)展 里沒有提供 ForEach() 方法,不過 All(IEnumerable
All() 的意思是,所有元素都符合條件則返回 true,所有只要有一個不符合條件,返回了 false,則中止遍歷,返回 false;Any() 的意思是只要發(fā)現(xiàn)有元素符合條件則返回 true。
Func
是一個公用委托。Func<...> 系列公用委托都用于委托帶有返回值的的方法,所有 Func<..., TResult> 都是最后一個參數(shù) TResult 代表返回值類型。
因此,C# 的遍歷輸出可以這樣實現(xiàn)
string[] names = { "Andy", "Jackson", "Yoo" }; names.All(name => { Console.WriteLine(name); return true; });
string[] names = { "Andy", "Jackson", "Yoo" }; names.Any(name => { Console.WriteLine(name); return false; });
JavaScript 的遍歷有 Lambda 就是好
JavaScript 的 Array 實現(xiàn)了 forEach 實例方法,即 Array.prototype.forEach()。
對于 JavaScript 的數(shù)組,可以這樣遍歷
var names = ["Andy", "Jackson", "Yoo"]; names.forEach(name => { console.log(name); });
對于 JavaScript 的偽數(shù)組,可以這樣
var names = { 0: "Andy", 1: "Jackson", 2: "Yoo", length: 3 }; [].forEach.call(names, name => { console.log(name); });jQuery 的遍歷
jQuery 是一個常用的 JavaScript 庫,它封裝的對象都是基于偽數(shù)組的,所以 jQuery 中經(jīng)常用到遍歷。除了網(wǎng)頁元素集合外,jQuery 也可以遍歷普通數(shù)組,有兩種方式
可以直接把數(shù)組作為第一個參數(shù),處理函數(shù)作為第二個參數(shù)調(diào)用 $.each()。
const names = ["Andy", "Jackson", "Yoo"]; $.each(names, (i, name) => { console.log(name); });
也可以把數(shù)組封裝成一個 jQuery 對象($(names)),再在這個 jQuery 對象上調(diào)用 eash() 方法。
const names = ["Andy", "Jackson", "Yoo"]; $(names).each((i, name) => { console.log(name); });
兩種方法的處理函數(shù)都一樣,但是要注意,這和原生 forEach() 的處理函數(shù)有點不同。jQuery 的 each() 處理函數(shù),第一個參數(shù)是序號,第二個參數(shù)是數(shù)組元素;而原生 forEach() 的處理函數(shù)正好相反,第一個參數(shù)是數(shù)組元素,第二個參數(shù)才是序號。
另外,$.each() 對偽數(shù)組同樣適用,不需要通過 call() 來調(diào)用。
Java 的遍歷String[] names = { "Andy", "Jackson", "Yoo" }; List過濾(篩選)數(shù)據(jù) 問題提出list = Arrays.asList(names); list.forEach(name -> { System.out.println(name); });
給出一組整數(shù),需要將其中能被 3 整除選出來
[46, 74, 20, 37, 98, 93, 98, 48, 33, 15]
期望結(jié)果
[93, 48, 33, 15]C# 中過濾使用 Where() 擴(kuò)展
int[] data = { 46, 74, 20, 37, 98, 93, 98, 48, 33, 15 }; int[] result = data.Where(n => n % 3 == 0).ToArray();
注意:Where() 的結(jié)果即不是數(shù)組也不是 List,需要通過 ToArray() 生成數(shù)組,或者通過 ToList() 生成列表。Linq 要在 ToArray() 或者 ToList() 或者其它某些操作的時候才會真正遍歷,依次執(zhí)行 Where() 參數(shù)提供的那個篩選函數(shù)。
JavaScript 中有 Array.prototype.filterconst data = [46, 74, 20, 37, 98, 93, 98, 48, 33, 15]; const result = data.filter(n => { return n % 3 === 0; });Java 中使用到 java.util.stream.*
Java 中可以通過 java.util.stream.IntStream.of() 來從數(shù)組生成 stream 對象
final int[] data = { 46, 74, 20, 37, 98, 93, 98, 48, 33, 15 }; int[] result = IntStream.of(data) .filter(n -> n % 3 == 0) .toArray();
需要注意的是,Arrays.asList(data).stream() 看起來也可以生成 stream 對象,但是通過調(diào)試會發(fā)現(xiàn),這是一個 Stream
List映射處理list = IntStream.of(data) .boxed() .collect(Collectors.toList());
映射處理是指將某種類型的集合,將其元素依次映射成另一種類型,產(chǎn)生一個新類型的集合。新集合中的每個元素都與原集中的同樣位置的元素有對應(yīng)關(guān)系。
問題提出這里提出一個精典的問題:成績轉(zhuǎn)等級,不過為了簡化代碼(switch 或多重 if 語句代碼比較長),改為判斷成績是否及格,60 分為及格線。
偷個懶,就用上個問題的輸入 [46, 74, 20, 37, 98, 93, 98, 48, 33, 15],
期望結(jié)果:
["REJECT","PASS","REJECT","REJECT","PASS","PASS","PASS","REJECT","REJECT","REJECT"]C# 通過 Select() 來進(jìn)行映射處理。
int[] scores = { 46, 74, 20, 37, 98, 93, 98, 48, 33, 15 }; string[] levels = scores .Select(score => score >= 60 ? "PASS" : "REJECT") .ToArray();JavaScript 通過 Array.prototype.map 來進(jìn)行映射處理。
const scores = [46, 74, 20, 37, 98, 93, 98, 48, 33, 15]; const levels = scores.map(score => { return score >= 60 ? "PASS" : "REJECT"; });Java 的 Stream 提供了 mapToObj() 等方法處理映射
final int[] scores = { 46, 74, 20, 37, 98, 93, 98, 48, 33, 15 }; String[] levels = IntStream.of(scores) .mapToObj(score -> score >= 60 ? "PASS" : "REJECT") .toArray(String[]::new);
與“篩選”示例不同,在“篩選”示例中,由于篩選結(jié)果是 IntStream,可以直接調(diào)用 InStream::toArray() 來得到 int[]。
但在這個示例中,mapToObj() 得到的是一個 Stream
查找表在數(shù)據(jù)結(jié)構(gòu)里的意義還是比較寬的,其中通過哈希算法實現(xiàn)的稱為哈希表。C# 中通常是用 Directory
現(xiàn)在有一個姓名列表,是按學(xué)號從 1~7 排列的,需要建立一個查找到,使之能通過姓名很容易找到對應(yīng)的學(xué)號。
["Andy", "Jackson", "Yoo", "Rose", "Lena", "James", "Stephen"]
期望結(jié)果
Andy => 1 Jackson => 2 Yoo => 3 Rose => 4 Lena => 5 James => 6 Stephen => 7C# 使用 ToDictionary()
string[] names = { "Andy", "Jackson", "Yoo", "Rose", "Lena", "James", "Stephen" }; int i = 1; Dictionarymap = names.ToDictionary(n => n, n => i++);
C# Linq 擴(kuò)展提供的若干方法都沒有將序號傳遞給處理函數(shù),所以上例中采用了臨時變量計數(shù)的方式來進(jìn)行。不過有一個看起來好看一點的辦法,用 Enumerable.Range() 先生成一個序號的序列,再基于這個序列來處理
string[] names = { "Andy", "Jackson", "Yoo", "Rose", "Lena", "James", "Stephen" }; IEnumerableJavaScript 的兩種處理辦法indexes = Enumerable.Range(0, names.Length); Dictionary map = indexes.ToDictionary(i => names[i], i => i + 1);
JavaScript 沒有提供從 [] 到 {} 的轉(zhuǎn)換函數(shù),不過要做這個轉(zhuǎn)換也不是好麻煩,用 forEach 遍歷即可
var map = (function() { var m = {}; names.forEach((name, i) => { m[name] = i + 1; }); return m; })();
為了不讓臨時變量污染外面的作用域,上面的示例中采用了 IEFE 的寫法。不過,如果用 Array.prototype.reduce 則可以讓代碼更簡潔一些
var map = names.reduce((m, name, i) => { m[name] = i + 1; return m; }, {});Java 的 Collectors
Java 的處理函數(shù)也沒有傳入序號,所以在 Java 中的實例和 C# 類似。不過,第一種方法不可用,因為 Java Lambda 的實現(xiàn)相當(dāng)于是匿名類對接口的實現(xiàn),只能訪問局部的 final 變量,i 要執(zhí)行 i++ 操作,顯然不是 final 的,所以只能用第二種辦法
final String[] names = { "Andy", "Jackson", "Yoo", "Rose", "Lena", "James", "Stephen" }; Mapmap = IntStream.range(0, names.length) .boxed() .collect(Collectors.toMap(i -> names[i], i -> i + 1));
匯總和聚合處理我只能說 .boxed() 是個大坑啊,一定要記得調(diào)。
匯總處理就是合計啊,平均數(shù)啊之類的,使用方式都差不多,所以以合計(Sum)為例。
匯總處理其實是聚合處理的一個特例,所以就同一個問題,再用普通的聚合處理方式再實現(xiàn)一次。
問題提出已知全班成績,求班總分,再次用到了那個數(shù)組
[46, 74, 20, 37, 98, 93, 98, 48, 33, 15]
期望結(jié)果:562
C# 的實現(xiàn)C# 可以直接使用 Sum() 方法求和
int[] scores = { 46, 74, 20, 37, 98, 93, 98, 48, 33, 15 }; int sum = scores.Sum();
聚合實現(xiàn)方式(用 Aggregate())
int[] scores = { 46, 74, 20, 37, 98, 93, 98, 48, 33, 15 }; int sum = scores.Aggregate(0, (total, score) => { return total + score; });
聚合實現(xiàn)方式要靈活得多,比如,改成乘法就可以算階乘。當(dāng)然用于其它更復(fù)雜的情況也不在話下。前面生成查找表的 JavaScript 部分就是采用聚合來實現(xiàn)的。
JavaScript 都是通過聚合來實現(xiàn)的const scores = [46, 74, 20, 37, 98, 93, 98, 48, 33, 15]; const sum = scores.reduce((total, score) => { return total + score; }, 0);
注意 C# 的初始值在前,JavaScript 的初始值在后,這是有區(qū)別的。參數(shù)順序嘛,注意一下就行了。
Java 中使用 Stream::reduce 進(jìn)行聚合處理IntStream 提供了 sum() 方法
final int[] scores = { 46, 74, 20, 37, 98, 93, 98, 48, 33, 15 }; final int sum = IntStream.of(scores).sum();
同樣也可以用 reduce 處理
final int[] scores = { 46, 74, 20, 37, 98, 93, 98, 48, 33, 15 }; final int sum = IntStream.of(scores) .reduce(0, (total, score) -> total + score);綜合應(yīng)用 問題提出
已知全班 7 個人,按學(xué)號 從 1~7 分別是
["Andy", "Jackson", "Yoo", "Rose", "Lena", "James", "Stephen"]
這 7 個人的成績按學(xué)號序,分別是
[66, 74, 43, 93, 98, 88, 83]
有 Student 數(shù)組結(jié)構(gòu)
Student { number: int name: string score: int }
要求得到全班 7 人的 student 數(shù)組,且該數(shù)組按分?jǐn)?shù)從高到低排序
C# 實現(xiàn)sealed class Student { public int Number { get; } public string Name { get; } public int Score { get; } public Student(int number, string name, int score) { Number = number; Name = name; Score = score; } public override string ToString() => $"[{Number}] {Name} : {Score}"; }
Student[] students = Enumerable.Range(0, names.Length) .Select(i => new Student(i + 1, names[i], scores[i])) .OrderByDescending(s => s.Score) .ToArray();
注意 C# 中排序有 OrderBy 和 OrderByDescending 兩個方法,一般情況下只需要給一個映射函數(shù),從原數(shù)據(jù)里找到要用于比較的數(shù)據(jù)即可使用其 >、< 等運算符進(jìn)行比較。如果比例起來比較復(fù)雜的,需要提供第二個參數(shù),一個 IComparer
class Student { constructor(number, name, score) { this._number = number; this._name = name; this._score = score; } get number() { return this._number; } get name() { return this._name; } get score() { return this._score; } toString() { return `[${this.number}] ${this.name} : ${this.score}`; } }
const names = ["Andy", "Jackson", "Yoo", "Rose", "Lena", "James", "Stephen"]; const scores = [66, 74, 43, 93, 98, 88, 83]; var students = names .map((name, i) => new Student(i + 1, name, scores[i])) .sort((a, b) => { return b.score - a.score; });
JavaScript 的排序則是直接給個比較函數(shù),根據(jù)返回的數(shù)值小于0、等于0或大于0來判斷是小于、等于還是大于。
Java 實現(xiàn)final class Student { private int number; private String name; private int score; public Student(int number, String name, int score) { this.number = number; this.name = name; this.score = score; } public int getNumber() { return number; } public String getName() { return name; } public int getScore() { return score; } @Override public String toString() { return String.format("[%d] %s : %d", getNumber(), getName(), getScore()); } }
final String[] names = { "Andy", "Jackson", "Yoo", "Rose", "Lena", "James", "Stephen" }; final int[] scores = { 66, 74, 43, 93, 98, 88, 83 }; Student[] students = IntStream.range(0, names.length) .mapToObj(i -> new Student(i + 1, names[i], scores[i])) .sorted((a, b) -> b.getScore() - a.getScore()) .toArray(Student[]::new);
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/65139.html
摘要:系列公用委托都用于委托帶有返回值的的方法,所有都是最后一個參數(shù)代表返回值類型。的字面對象據(jù)稱也是哈希實現(xiàn)。 Java 丟了好多年,最近在揀起來,首先當(dāng)然是了解這么多年來它的變化,于是發(fā)現(xiàn)了 Java 8 的java.util.stream。在學(xué)習(xí)和試驗的過程中,相比較于 C# 和 javascript,有那么些心得,作文以記之。 早些時間寫過一篇《ES6 的 for..of 和 Ge...
摘要:集合框架的基本接口類層次結(jié)構(gòu)其中表示接口,表示實現(xiàn)類和在實際開發(fā)中,需要將使用的對象存儲于特定數(shù)據(jù)結(jié)構(gòu)的容器中。實例是迭代器,擁有兩個方法方法迭代器用于遍歷集合元素。返回值則是轉(zhuǎn)換后的數(shù)組,該數(shù)組會保存集合中的所有元素。 Java Collections Framework是Java提供的對集合進(jìn)行定義,操作,和管理的包含一組接口,類的體系結(jié)構(gòu)。 Java集合框架的基本接口/類層次結(jié)構(gòu)...
閱讀 2684·2021-10-22 09:55
閱讀 2008·2021-09-27 13:35
閱讀 1267·2021-08-24 10:02
閱讀 1478·2019-08-30 15:55
閱讀 1198·2019-08-30 14:13
閱讀 3471·2019-08-30 13:57
閱讀 1975·2019-08-30 11:07
閱讀 2447·2019-08-29 17:12