文:宋瑞文(媽媽監督核電廠聯盟特約撰述)
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※台北網頁設計公司這麼多該如何選擇?
※智慧手機時代的來臨,RWD網頁設計為架站首選
※評比南投搬家公司費用收費行情懶人包大公開
※幫你省時又省力,新北清潔一流服務好口碑
※回頭車貨運收費標準
為鼓勵購買低汙染的環保車輛,電動汽車將再延長牌照稅免稅期 3 年。包括電動小客車、巴士與貨車,免徵牌照稅優惠將可持續至 2018 年 1 月 5 日為止。 為基於扶植國內電動車研發製造的需要,立法院財政委員會 12 日將審查由行政院提出的用牌照稅法修正草案,授權給地方政府對以電能為動力的電動汽車,免徵牌照稅優惠期間,可以再延長 3 年。經濟日報指出,這項減稅法案可望趕在立法院本會期結束前完成修法程序,以便接續提供減免。 財政部指出,免徵電動車使用照稅優惠措施自 2012 年 1 月 5 日施行至今,國庫釋出的免稅利益將近新台幣 1,000 萬元,平均每年約為 300 萬元。過去 3 年,申請免稅的電動車由 319 輛成長到 574 輛,減稅金額也從約 200 萬元倍增至近 400 萬元。財政部認為,電動車申請免稅案件逐年增加,代表電動車的使用與購買意願也在上升。
本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※台北網頁設計公司這麼多該如何選擇?
※智慧手機時代的來臨,RWD網頁設計為架站首選
※評比南投搬家公司費用收費行情懶人包大公開
※幫你省時又省力,新北清潔一流服務好口碑
※回頭車貨運收費標準

算法的主題思想:
1.優秀的算法因為能夠解決實際問題而變得更為重要;
2.高效算法的代碼也可以很簡單;
3.理解某個實現的性能特點是一個挑戰;
4.在解決同一個問題的多種算法之間進行選擇時,科學方法是一種重要的工具;
5.迭代式改進能夠讓算法的效率越來越高效;
1. 動態連通性
動態連接:輸入是一對整數對的序列,其中每個整數代表某種類型的對象(或觸點),我們將整數對p q 解釋為意味着p連接到q。我們假設“連接到”是等價關係:
對稱性:如果p連接到q,則q 連接到p。
傳遞性:如果p連接到q且q 連接到r,則p連接到r。
自反性:p與p連接。
等價關係將對象劃分為多個等價類 或連接的組件。等價類稱為連通分量或分量。
我們的目標是編寫一個程序,以從序列中過濾掉多餘的對:當程序從輸入中讀取整數對 p q時,只有在該對點不等價的情況下,才應將對寫入到輸出中,並且將p連接到q。如果等價,則程序應忽略整數對pq 並繼續讀取下對。
動態連通性問題的應用:
1.網絡
2.變量名等價性
3.數學集合
在更高的抽象層次上,可以將輸入的所有整數看做屬於不同的數學集合。
2. 定義問題
設計算法的第一個任務就是精確地定義問題。
算法解決的問題越大,它完成任務所需的時間和空間可能越多。我們不可能預先知道這其間的量化關係,通常只會在發現解決問題很困難,或是代價巨大,或是發現算法所提供的信息比原問題所需要的更加有用時修改問題。例如,連通性問題只要求我們的程序能夠判斷出給定的整數對是否相連,但並沒有要求給出兩者之間的通路上的所有連接。這樣的要求更難,並會得出另一組不同的算法。
為了定義和說明問題,先設計一份API 來封裝基本操作: 初始化,連接兩個觸點,查找某個觸點的分量 ,判斷兩個觸點是否屬於同一分量,分量的數量:
/// <summary> /// 動態連通API /// </summary> public interface IUnionFind { /// <summary> /// 連接 /// </summary> /// <param name="p"></param> /// <param name="q"></param> void Union(int p, int q); /// <summary> /// 查找觸點 p 的分量標識符 /// </summary> /// <param name="p"></param> /// <returns></returns> int Find(int p); /// <summary> /// 判斷兩個觸點是否處於同一分量 /// </summary> /// <param name="p"></param> /// <param name="q"></param> /// <returns></returns> bool Connected(int p, int q); /// <summary> /// 連通分量的數量 /// </summary> /// <returns></returns> int Count(); }
為解決動態連通性問題設計算法的任務轉化為實現這份API:
1. 定義一種數據結構表示已知的連接;
2. 基於此數據結構高效的實現API的方法;
數據結構的性質會直接影響算法的效率。這裏,以觸點為索引,觸點和連接分量都是用 int 值表示,將會使用分量中某個觸點的值作為分量的標識符。所以,一開始,每個觸點都是只含有自己的分量,分量標識符為觸點的值。由此,可以初步實現一部分方法:
public class FirstUnionFind:IUnionFind { private int[] id;//* 分量id 以觸點作為索引 private int count;//分量數量 public FirstUnionFind(int n) { count = n; id = new int[n]; for (var i = 0; i < n; i++) { id[i] = i; // 第一個 i 作為觸點,第二個 i 作為觸點的值 } } public int Count() { return count; } public bool Connected(int p, int q) { return Find(p) == Find(q); } public int Find(int p) { } public void Union(int p, int q) { } }
Union-find 的成本模型 是數組的訪問次數(無論讀寫)。
3. quick-find算法實現
quick-find 算法是保證當且僅當 id[p] 等於 id[q] 時,p 和 q 是連通的。也就是說,在同一個連通分量中的所有觸點在 id[ ] 中的值全部相等。
所以 Find 方法只需返回 id[q],Union 方法需要先判斷 Find(p) 是否等於 Find(q) ,若相等直接返回;若不相等,需要將 q 所在的連通分量中所有觸點的 id [ ] 值全部更新為 id[p]。
public class QuickFindUF: IUnionFind { private int[] id;//* 分量id 以觸點作為索引 private int count;//分量數量 public QuickFindUF(int n) { count = n; id = new int[n]; for (var i = 0; i < n; i++) { id[i] = i; // 第一個 i 作為觸點,第二個 i 作為觸點的值 } } public int Count() { return count; } public bool Connected(int p, int q) { return Find(p) == Find(q); } public int Find(int p) { return id[p]; } public void Union(int p, int q) { var pID = Find(p); var qID = Find(q); if (pID == qID) return; for (var i = 0; i < id.Length; i++) { if (id[i] == qID) id[i] = pID; } count--; //連通分量減少 } public void Show() { for(var i = 0;i<id.Length;i++) Console.WriteLine("索引:"+i+",值:"+ id[i] ); Console.WriteLine("連通分量數量:"+count); } }
算法分析
Find() 方法只需訪問一次數組,所以速度很快。但是對於處理大型問題,每對輸入 Union() 方法都需要掃描整個數組。
每一次歸併兩個分量的 Union() 方法訪問數組的次數在 N+3 到 2N+1 之間。由代碼可知,兩次 Find 操作訪問兩次數組,掃描數組會訪問N次,改變其中一個分量中所有觸點的值需要訪問 1 到 N – 1 次(最好情況是該分量中只有一個觸點,最壞情況是該分量中有 N – 1個觸點),2+N+N-1。
如果使用quick-find 算法來解決動態連通性問題並且最後只得到一個連通分量,至少需要調用 N-1 次Union() 方法,那麼至少需要 (N+3)(N-1) ~ N^2 次訪問數組,是平方級別的。
4. quick-union算法實現
quick-union 算法重點提高 union 方法的速度,它也是基於相同的數據結構 — 已觸點為索引的 id[ ] 數組,但是 id[ ] 的值是同一分量中另一觸點的索引(名稱),也可能是自己(根觸點)——這種聯繫成為鏈接。
在實現 Find() 方法時,從給定觸點,鏈接到另一個觸點,知道到達根觸點,即鏈接指向自己。同時修改 Union() 方法,分別找到 p q 的根觸點,將其中一個根觸點鏈接到根觸點。
public class QuickUnionUF : IUnionFind { private int[] id; private int count; public QuickUnionUF(int n) { count = n; id = new int[n]; for (var i = 0; i < n; i++) { id[i] = i; // 第一個 i 作為觸點,第二個 i 作為觸點的值 } } public int Count() { return count; } public bool Connected(int p, int q) { return Find(p) == Find(q); } public int Find(int p) { while (p != id[p]) p = id[p]; return p; } public void Union(int p, int q) { var pRoot = Find(p); var qRoot = Find(q); if (pRoot == qRoot) return; id[pRoot] =qRoot;
count--; //連通分量減少 } public void Show() { for (var i = 0; i < id.Length; i++) Console.WriteLine("索引:" + i + ",值:" + id[i]); Console.WriteLine("連通分量數量:" + count); } }
森林表示
id[ ] 數組用父鏈接的形式表示一片森林,用節點表示觸點。無論從任何觸點所對應的節點隨着鏈接查找,最後都將到達含有該節點的根節點。初始化數組之後,每個節點的鏈接都指向自己。
算法分析
定義:一棵樹的大小是它的節點的數量。樹中一個節點的深度是它到根節點的路徑上鏈接數。樹的高度是它的所有節點中的最大深度。
quick-union 算法比 quick-find 算法更快,因為它對每對輸入不需要遍歷整個數組。
分析quick-union 算法的成本比 quick-find 算法的成本要困難,因為quick-union 算法依賴於輸入的特點。在最好的情況下,find() 方法只需訪問一次數組就可以得到一個觸點的分量表示;在最壞情況下,需要 2i+1 次數組訪問(i 時觸點的深度)。由此得出,該算法解決動態連通性問題,在最佳情況下的運行時間是線性級別,最壞情況下的輸入是平方級別。解決了 quick-find 算法中 union() 方法總是線性級別,解決動態連通性問題總是平方級別。
quick-union 算法中 find() 方法訪問數組的次數為 1(到達根節點只需訪問一次) 加上 給定觸點所對應節點的深度的兩倍(while 循環,一次讀,一次寫)。union() 訪問兩次 find() ,如果兩個觸點不在同一分量還需加一次寫數組。
假設輸入的整數對是有序的 0-1, 0-2,0-3 等,N-1 對之後N個觸點將全部處於相同的集合之中,且得到的樹的高度為 N-1。由上可知,對於整數對 0-i , find() 訪問數組的次數為 2i + 1,因此,處理 N 對整數對所需的所有訪問數組的總次數為 3+5+7+ ……+(2N+1) ~ n^2
5.加權 quick-union 算法實現
簡單改動就可以避免 quick-union算法 出現最壞情況。quick-union算法 union 方法是隨意將一棵樹連接到另一棵樹,改為總是將小樹連接到大樹,這需要記錄每一棵樹的大小,稱為加權quick-union算法。
代碼:
public class WeightedQuickUnionUF: IUnionFind { int[] sz;//以觸點為索引的 各個根節點對應的分量樹大小 private int[] id; private int count; public WeightedQuickUnionUF(int n) { count = n; id = new int[n]; sz = new int[n]; for (var i = 0; i < n; i++) { id[i] = i; // 第一個 i 作為觸點,第二個 i 作為觸點的值 sz[i] = 1; } } public int Count() { return count; } public bool Connected(int p, int q) { return Find(p) == Find(q); } public int Find(int p) { while (p != id[p]) p = id[p]; return p; } public void Union(int p, int q) { var pRoot = Find(p); var qRoot = Find(q); if (pRoot == qRoot) return; if (sz[pRoot] < sz[qRoot]) { id[pRoot] = qRoot; } else { id[qRoot] = pRoot; } count--; //連通分量減少 } public void Show() { for (var i = 0; i < id.Length; i++) Console.WriteLine("索引:" + i + ",值:" + id[i]); Console.WriteLine("連通分量數量:" + count); } }
算法分析
加權 quicj-union 算法最壞的情況:
這種情況,將要被歸併的樹的大小總是相等的(且總是 2 的 冥),都含有 2^n 個節點,高度都正好是 n 。當歸併兩個含有 2^n 個節點的樹時,得到的樹含有 2 ^ n+1 個節點,高度增加到 n+1 。
節點大小: 1 2 4 8 2^k = N
高 度: 0 1 2 3 k
k = logN
所以加權 quick-union 算法可以保證對數級別的性能。
對於 N 個觸點,加權 quick-union 算法構造的森林中的任意節點的深度最多為logN。
對於加權 quick-union 算法 和 N 個觸點,在最壞情況下 find,connected 和 union 方法的成本的增長量級為 logN。
對於動態連通性問題,加權 quick-union 算法 是三種算法中唯一可以用於解決大型問題的算法。加權 quick-union 算法 處理 N 個觸點和 M 條連接時最多訪問數組 c M logN 次,其中 c 為常數。
三個算法處理一百萬個觸點運行時間對比:
三個算法性能特點:
6.最優算法 – 路徑壓縮
在檢查節點的同時將它們直接連接到根節點。
實現:為 find 方法添加一個循環,將在路徑上的所有節點都直接鏈接到根節點。完全扁平化的樹。
研究各種基礎問題的基本步驟:
1. 完整而詳細地定義問題,找出解決問題所必須的基本抽象操作並定義一份API。
2. 簡潔地實現一種初級算法,給出一個精心組織的開發用例並使用實際數據作為輸入。
3. 當實現所能解決的問題的最大規模達不到期望時決定改進還是放棄。
4. 逐步改進實現,通過經驗性分析和數學分析驗證改進后的效果。
5. 用更高層次的抽象表示數據結構或算法來設計更高級的改進版本。
6. 如果可能盡量為最壞情況下的性能提供保證,但在處理普通數據時也要有良好的性能。
7.在適當的時候將更細緻的深入研究留給有經驗的研究者並解決下一個問題。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※台北網頁設計公司這麼多該如何選擇?
※智慧手機時代的來臨,RWD網頁設計為架站首選
※評比南投搬家公司費用收費行情懶人包大公開
※幫你省時又省力,新北清潔一流服務好口碑
※回頭車貨運收費標準
在中國的全球新能源汽車大會上,北京市科委新能源與新材料處處長許心超透露,北京市新能源汽車準入方式有所調整,由先前的新能源汽車目錄方式改為備案方式,車型只要備案即可在北京銷售、上牌。 先前規定,按照《北京市示範應用新能源小客車生企業及品目錄》,北京市共有 7 款新能源汽車可在備案之後直接銷售、上牌。而這次許心超表示,按照中央的要求,準入方式也在改變,主要採取備案制,只要備案了就可銷售,政府則加強事後監管。
這意味著所有中國純電動汽車都可以進京銷售、上牌,享受財政補貼,而不再像以前必須要先進入嚴格的北京市新能源汽車目錄。 另一方面,為了讓純電動汽車的使用者迅速找到充電樁,相關部門也在進行改進,一是和百度合作,標注所有充電樁的電子地圖將很快上線;二是印製北京充電樁地圖;三是辦充電體驗周活動,在 2 月 2 日至 6 日,將分 2 次聯合所有北京的汽車企業,做充電實際體驗。
本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※台北網頁設計公司這麼多該如何選擇?
※智慧手機時代的來臨,RWD網頁設計為架站首選
※評比南投搬家公司費用收費行情懶人包大公開
※幫你省時又省力,新北清潔一流服務好口碑
※回頭車貨運收費標準
過去幾個月來,蘋果打算進軍終極行動裝置──汽車的傳言甚囂塵上。最新消息更顯示,蘋果正在加緊鞭策研發團隊,希望能在 2020 年產出旗下第一輛電動車。無獨有偶,數小時前才剛洩漏的法院文件顯示,美國汽車鋰離子電池與電池系統廠商 A123 Systems Inc. 控訴蘋果挖角多名重要的工程師,或許蘋果開發電動車是真有其事。 彭博社 20 日引述未具名消息人士報導,蘋果最快 2020 年就會開始量產電動車。一般來說,有經驗的汽車業者想要研發一款全新汽車、通常得花上 5 至 7 年的時間,假如要從零開始、時間更得費上 10 年之久。蘋果設定了如此緊迫的量產時程,凸顯了該公司對汽車領域的強大企圖心。 相較之下,特斯拉(Tesla Motors Inc.)、通用汽車(General Motors Co.)這兩家汽車大廠,則都預定要在 2017 年發表一輛單次充電後可行駛超過 200 英里、售價低於 4 萬美元的電動車。 蘋果的汽車團隊過去幾個月加緊聘人、目前已有 200 人之譜,而最新延攬的員工大多是電池、機器人專才。不過,根據消息人士的說法,倘若汽車的進展不如預期,蘋果仍可能推延開發案、或甚至直接抽手退出。
本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※台北網頁設計公司這麼多該如何選擇?
※智慧手機時代的來臨,RWD網頁設計為架站首選
※評比南投搬家公司費用收費行情懶人包大公開
※幫你省時又省力,新北清潔一流服務好口碑
※回頭車貨運收費標準

.NET 5 終於在 6月25日 發布了第六個預覽版,隨之而來的是更多的新特性加入到了 C# 9 Preview 中,這個系列也可以繼續往下寫了,廢話不多說,今天來看一下 Top-level programs 和 Extending Partial Methods 兩大新特性。
下載最新的 .net 5 preview 6。
下載最新的 Visual Studio 2019 version 16.7 Preview 3.1
如果大家玩過 python,應該知道在 xxx.py 中寫一句 print,這程序就能跑起來了,簡單高效又粗暴,很開心的是這特性被帶到了C# 9.0 中。
using System;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
System.Console.WriteLine("Hello World!");
這就有意思了,Main入口函數去哪了? 沒它的話,JIT還怎麼編譯代碼呢? 想知道答案的話用 ILSpy 反編譯看一下就好啦!
.class private auto ansi abstract sealed beforefieldinit $Program
extends [System.Runtime]System.Object
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
// Methods
.method private hidebysig static
void $Main (
string[] args
) cil managed
{
// Method begins at RVA 0x2050
// Code size 18 (0x12)
.maxstack 8
.entrypoint
IL_0000: ldstr "Hello World!"
IL_0005: call void [System.Console]System.Console::WriteLine(string)
IL_000a: nop
IL_000b: call string [System.Console]System.Console::ReadLine()
IL_0010: pop
IL_0011: ret
} // end of method $Program::$Main
} // end of class $Program
從 IL 上看,類變成了 $Program, 入口方法變成了 $Main, 這就好玩了,在我們的印象中入口函數必須是 Main,否則編譯器會給你一個大大的錯誤,你加了一個 $ 符號,那CLR還能認識嗎? 能不能認識我們用 windbg 看一些託管和非託管堆棧,看看有什麼新發現。
0:010> ~0s
ntdll!NtReadFile+0x14:
00007ffe`f8f8aa64 c3 ret
0:000> !dumpstack
OS Thread Id: 0x7278 (0)
Current frame: ntdll!NtReadFile + 0x14
Child-SP RetAddr Caller, Callee
0000008551F7E810 00007ffed1e841dc (MethodDesc 00007ffe4020d500 + 0x1c System.Console.ReadLine()), calling 00007ffe400ab090
0000008551F7E840 00007ffe4014244a (MethodDesc 00007ffe401e58f0 + 0x3a $Program.$Main(System.String[])), calling 00007ffe40240f58
0000008551F7E880 00007ffe9fcc8b43 coreclr!CallDescrWorkerInternal + 0x83 [F:\workspace\_work\1\s\src\coreclr\src\vm\amd64\CallDescrWorkerAMD64.asm:101]
0000008551F7E8C0 00007ffe9fbd1e03 coreclr!MethodDescCallSite::CallTargetWorker + 0x263 [F:\workspace\_work\1\s\src\coreclr\src\vm\callhelpers.cpp:554], calling coreclr!CallDescrWorkerWithHandler [F:\workspace\_work\1\s\src\coreclr\src\vm\callhelpers.cpp:56]
0000008551F7E950 00007ffe9fb8c4e5 coreclr!MethodDesc::IsVoid + 0x21 [F:\workspace\_work\1\s\src\coreclr\src\vm\method.cpp:1098], calling coreclr!MetaSig::IsReturnTypeVoid [F:\workspace\_work\1\s\src\coreclr\src\vm\siginfo.cpp:5189]
0000008551F7EA00 00007ffe9fb8c4bf coreclr!RunMainInternal + 0x11f [F:\workspace\_work\1\s\src\coreclr\src\vm\assembly.cpp:1488], calling coreclr!MethodDescCallSite::CallTargetWorker [F:\workspace\_work\1\s\src\coreclr\src\vm\callhelpers.cpp:266]
0000008551F7EB30 00007ffe9fb8c30a coreclr!RunMain + 0xd2 [F:\workspace\_work\1\s\src\coreclr\src\vm\assembly.cpp:1559], calling coreclr!RunMainInternal [F:\workspace\_work\1\s\src\coreclr\src\vm\assembly.cpp:1459]
從上面堆棧的流程圖看: coreclr!RunMain -> coreclr!MethodDesc -> coreclr!CallDescrWorkerInternal -> $Program.$Main, 確實被調用了,不過有一個重大發現,在 $Program.$Main 調用之前底層的 CLR 讀取了 方法描述符,這就是一個重大突破點,方法描述符在哪裡呢? 可以用 ildasm 去看一下元數據列表。
可以看到,入口函數那裡打上了一個 ENTRYPOINT 標記,這就說明入口函數名其實是可以隨便更改的,只要被 ENTRYPOINT打上標記即可,CoreCLR就能認的出來~~~
我們知道 部分方法 是一個很好的樁函數,而且在 C# 3.0 中就已經實現了,那時候給我們增加了很多限制,如下圖:
翻譯過來就是:
部分方法的簽名必須一致
方法必須返回void
不允許使用訪問修飾符,而且還是隱式私有的。
在 C# 9.0 中放開了對 方法簽名 的所有限制,正如 issue 總結:
這是一個非常好的消息,現在你的部分方法上可以加上各種類型的返回值啦,這裏我舉一個例子:
class Program
{
static void Main(string[] args)
{
var person = new Person();
Console.WriteLine(person.Run("jack"));
}
}
public partial class Person
{
public partial string Run(string name);
}
public partial class Person
{
public partial string Run(string name) => $"{name}:開溜了~";
}
然後我們用 ILSpy 簡單看看底層怎麼玩的,如下圖可以看到其實就是一個簡單的合成,對吧。
現在我有想法了,如果我不給 Run 方法實現會怎麼樣? 把下面的 partial 類註釋掉看一下。
從報錯信息看,可訪問的修飾符必須要有方法實現,還以為直接編譯的時候抹掉呢。 這就起不到樁函數的作用:-D,不過這個特性還是給了我們更多的可能用的到的應用場景吧。
本篇兩個特性還是非常實用的,Top-level programs 讓我們可以寫更少的代碼,甚至拿起 記事本 都可以快捷的編寫類似一次性使用的測試代碼, Partial Methods 特性留給大家補充吧,我基本上算是沒用過 (┬_┬)。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※台北網頁設計公司這麼多該如何選擇?
※智慧手機時代的來臨,RWD網頁設計為架站首選
※評比南投搬家公司費用收費行情懶人包大公開
※幫你省時又省力,新北清潔一流服務好口碑
※回頭車貨運收費標準

Tushare是一個免費、開源的python財經數據接口包。主要實現對股票等金融數據從數據採集、清洗加工 到 數據存儲的過程,用戶可以免費(部分數據的下載有積分限制)的通過它提供的財經接口獲取股票交易、期貨等財經信息,功能非常強大。該接口和直接到各財經網站爬數據相比,最大的優勢就是快,去傳統財經網站爬數據,好多關鍵性的股票信息只能一隻股一隻股爬,而Tu Share的API,一個調用可以獲得一天的全部數據,速度差了好幾個數量級。另外一方面各財經網站的接口的API沒有對外文檔化,隨時可能變化,而Tu Share的API有正式的文檔化相對比較穩定。
該網站使用積分制來控制數據的訪問權限,如果想要訪問數據,先要到下面這個網址完成註冊,https://tushare.pro/register。註冊完成后,可以需要到個人主頁中拷貝Token,這個Token會在以後的訪問中用到,步驟如下
1、登錄成功后,點擊右上角->個人主頁
2、 在“用戶中心”中點擊“接口TOKEN”
3、 可以點擊右側複製按鈕複製token
Tushare HTTP數據獲取的方式,採用了post的機制,通過提交JSON body參數,就可以獲得您想要的數據。具體參數說明如下:
api_name:接口名稱,比如stock_basic
token :用戶唯一標識,可通過登錄pro網站獲取
params:接口參數,如daily接口中start_date和end_date
fields:字段列表,用於接口獲取指定的字段,以逗號分隔,如”open,high,low,close”
code: 接口返回碼,2002表示權限問題。
msg:錯誤信息,比如“系統內部錯誤”,“沒有權限”等
data:數據,data里包含fields和items字段,分別為字段和數據內容
1、在Visual Studio中安裝下面幾個包:Microsoft.Extensions.Http、Newtonsoft.Json
2、封裝方法,實現對REST web service的調用
public interface IHttpClientUtility { string HttpClientPost(string url, object datajson); }
public class HttpClientUtility : IHttpClientUtility { public HttpClientUtility() { } public string HttpClientPost(string url, object datajson) { using (HttpClient httpClient = new HttpClient()) //http對象 { httpClient.DefaultRequestHeaders.Accept.Clear(); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); httpClient.Timeout = new TimeSpan(0, 0, 5); //轉為鏈接需要的格式 HttpContent httpContent = new JsonContent(datajson); //請求 HttpResponseMessage response = httpClient.PostAsync(url, httpContent).Result; if (response.IsSuccessStatusCode) { Task<string> t = response.Content.ReadAsStringAsync(); return t.Result; } throw new Exception("調用失敗"); } } }
public class JsonContent : StringContent { public JsonContent(object value) : base(JsonConvert.SerializeObject(value), Encoding.UTF8, "application/json") { } public JsonContent(object value, string mediaType) : base(JsonConvert.SerializeObject(value), Encoding.UTF8, mediaType) { } }
3、封裝對Tu Share API的調用
public class TuShareUtility { private IHttpClientUtility _httpClientUtility; private string _url = "http://api.waditu.com/"; public TuShareUtility(IHttpClientUtility httpClientUtility) { _httpClientUtility = httpClientUtility; } /// <summary> /// 調用TuShare API /// </summary> /// <param name="apiName"></param> /// <param name="parmaMap"></param> /// <param name="fields"></param> /// <returns></returns> public DataTable GetData(string apiName,Dictionary<string,string> parmaMap,params string[] fields) { var tuShareParamObj=new TuShareParamObj(){ ApiName = apiName ,Params = parmaMap,Fields = string.Join(",",fields)}; //做Http調用 var result=_httpClientUtility.HttpClientPost(_url, tuShareParamObj); //將返回結果序列化成對象 var desResult=JsonConvert.DeserializeObject<TuShareResult>(result); //如果調用失敗,拋出異常 if(!string.IsNullOrEmpty(desResult.Msg)) throw new Exception(desResult.Msg); //返回結果分成兩部分,一部分是列頭信息,另一部分是數據本身,用這兩部分數據可以構建DataTable DataTable dt = new DataTable(); foreach (var dataField in desResult.Data.Fields) { dt.Columns.Add(dataField); } foreach (var dataItemRow in desResult.Data.Items) { var newdr=dt.NewRow(); for (int i=0;i< dataItemRow.Length;i++) { newdr[i] = dataItemRow[i]; } dt.Rows.Add(newdr); } return dt; } private class TuShareParamObj { [JsonProperty("api_name")] public string ApiName { get; set; } [JsonProperty("token")] public string Token { get; } = "****************";//你的Token [JsonProperty("params")] public Dictionary<string, string> Params { get; set; } [JsonProperty("fields")] public string Fields { get; set; } } private class TuShareData { [JsonProperty("fields")] public string[] Fields { get; set; } [JsonProperty("items")] public string[][] Items { get; set; } } private class TuShareResult { [JsonProperty("code")] public string Code { get; set; } [JsonProperty("msg")] public string Msg { get; set; } [JsonProperty("data")] public TuShareData Data { get; set; } } }
4、調用示例
獲得日線行情,整個過程1秒左右,返回6月24日,股票相關交易信息,代碼如下,(該網站的其它接口定義可以到https://tushare.pro/document/2查看)
var tuShareUtility=new TuShareUtility(); Dictionary<string, string> p = new Dictionary<string, string>(); p["trade_date"] = "20200624"; var table = tuShareUtility.GetData("daily", p, "");
返回如下結果
返回字段說明
| 名稱 | 類型 | 描述 |
|---|---|---|
| ts_code | str | 股票代碼 |
| trade_date | str | 交易日期 |
| open | float | 開盤價 |
| high | float | 最高價 |
| low | float | 最低價 |
| close | float | 收盤價 |
| pre_close | float | 昨收價 |
| change | float | 漲跌額 |
| pct_chg | float | 漲跌幅 (未復權,如果是復權請用 通用行情接口 ) |
| vol | float | 成交量 (手) |
| amount | float | 成交額 (千元) |
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※台北網頁設計公司這麼多該如何選擇?
※智慧手機時代的來臨,RWD網頁設計為架站首選
※評比南投搬家公司費用收費行情懶人包大公開
※幫你省時又省力,新北清潔一流服務好口碑
※回頭車貨運收費標準

最近在寫一個多模塊的SpringBoot項目,基於過程總了一些總結,故把SpringBoot多個模塊的項目創建記錄下來。
首先,先建立一個父工程:
(1)在IDEA工具欄選擇File->New->Project
(2)選擇Spring Initializr,默認選擇Default,然後點擊Next:
(3)在輸入框填寫以下截圖內容,點擊Next
(4)直接點Next,無需選擇
(5)直接點擊Finish完成創建
(6)按照以上步驟,可以生成以下的項目目錄結構:
(7)這時把沒用的.mvn目錄,src目錄,mvnw還有mvnw.cmd都刪除,最終只保留.gitignore和pom.xml,若是web項目,可在該pom.xml里添加以下依賴:
1 <!--web特徵--> 2 <dependency> 3 <groupId>org.springframework.boot</groupId> 4 <artifactId>spring-boot-starter-web</artifactId> 5 <version>2.3.1.RELEASE</version> 6 </dependency>
最終得到以下的父結構目錄:
以上是創建父模塊,下面創建子模塊:
(1)在父模塊的根目錄fte上點右鍵,在彈出的框里選擇New->Module
(2)選擇Maven,點擊Next
(3)填寫以下內容,點擊Next
(4)填寫Module,點擊Finish
(5)同理添加fte-controller,fte-dao,fte-service,fte-web,最終得到以下的目錄結構:
(6)增加模塊之間的依賴:
controller層添加以下依賴:
1 <dependencies> 2 <dependency> 3 <groupId>com.example</groupId> 4 <artifactId>fte-common</artifactId> 5 <version>0.0.1-SNAPSHOT</version> 6 </dependency> 7 8 <dependency> 9 <groupId>com.example</groupId> 10 <artifactId>fte-dao</artifactId> 11 <version>0.0.1-SNAPSHOT</version> 12 </dependency> 13 14 <dependency> 15 <groupId>com.example</groupId> 16 <artifactId>fte-service</artifactId> 17 <version>0.0.1-SNAPSHOT</version> 18 </dependency> 19 </dependencies>
service層添加以下依賴:
1 <dependencies> 2 <dependency> 3 <groupId>com.example</groupId> 4 <artifactId>fte-dao</artifactId> 5 <version>0.0.1-SNAPSHOT</version> 6 </dependency> 7 </dependencies>
(7)測試
在fte-controller創建com.zhu.fte.web包,增加以下兩個類:
fteWebApplication類:
1 package com.zhu.fte.web; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 6 @SpringBootApplication 7 public class fteWebApplication { 8 public static void main(String[] args) { 9 SpringApplication.run(fteWebApplication.class,args); 10 } 11 }
DemoController類
1 package java.com.zhu.fte.web; 2 3 import org.springframework.web.bind.annotation.GetMapping; 4 import org.springframework.web.bind.annotation.RequestMapping; 5 import org.springframework.web.bind.annotation.RestController; 6 7 @RestController 8 @RequestMapping("demo") 9 public class DemoController { 10 11 @GetMapping("test") 12 public String test(){ 13 return "hello world"; 14 } 15 16 }
運行發現出現錯誤:
出現錯誤:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:test (default-test) on project fte-common: Execution default-test of goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:test failed: Plugin org.apache.maven.plugins:maven-surefire-plugin:2.22.2 or one of its dependencies could not be resolved: Could not transfer artifact junit:junit:jar:4.12 from/to central (https://repo.maven.apache.org/maven2): Connect to repo.maven.apache.org:443 [repo.maven.apache.org/151.101.52.215] failed: Connection timed out: connect -> [Help 1]
把缺少的org.apache.maven.plugins手動放到父工程的pom.xml里
1 <build> 2 <plugins> 3 <plugin> 4 <groupId>org.apache.maven.plugins</groupId> 5 <artifactId>maven-clean-plugin</artifactId> 6 <version>2.5</version> 7 </plugin> 8 <plugin> 9 <groupId>org.apache.maven.plugins</groupId> 10 <artifactId>maven-source-plugin</artifactId> 11 <version>2.2</version> 12 </plugin> 13 <plugin> 14 <groupId>org.apache.maven.plugins</groupId> 15 <artifactId>maven-compiler-plugin</artifactId> 16 <version>3.0</version> 17 <configuration> 18 <source>1.8</source> 19 <target>1.8</target> 20 <encoding>${file.encoding}</encoding> 21 <!--編譯的時候方法不改變方法參數名稱,用於支持使用反射獲取方法參數名稱--> 22 <compilerArgument>-parameters</compilerArgument> 23 </configuration> 24 </plugin> 25 <plugin> 26 <groupId>org.apache.maven.plugins</groupId> 27 <artifactId>maven-install-plugin</artifactId> 28 <version>2.4</version> 29 </plugin> 30 <plugin> 31 <groupId>org.apache.maven.plugins</groupId> 32 <artifactId>maven-jar-plugin</artifactId> 33 <version>2.4</version> 34 <configuration> 35 <archive> 36 <manifest> 37 <addDefaultImplementationEntries>true 38 </addDefaultImplementationEntries> 39 </manifest> 40 </archive> 41 </configuration> 42 </plugin> 43 44 <plugin> 45 <groupId>org.apache.maven.plugins</groupId> 46 <artifactId>maven-surefire-plugin</artifactId> 47 <version>2.13</version> 48 <configuration> 49 <argLine>-Xmx512M -Dfile.encoding=${file.encoding}</argLine> 50 </configuration> 51 </plugin> 52 </plugins> 53 </build>
運行fteWebApplication類里的main方法,默認端口為8080,訪問http://localhost:8080/demo/test,正常出現以下情況:
按照以上步驟,就可以初步建立SpringBoot多模塊的項目,下一章將基於這個基礎搭建Mybatis以及其逆向工程。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※台北網頁設計公司這麼多該如何選擇?
※智慧手機時代的來臨,RWD網頁設計為架站首選
※評比南投搬家公司費用收費行情懶人包大公開
※幫你省時又省力,新北清潔一流服務好口碑
※回頭車貨運收費標準

當我們將input框的類型設置為密碼框的時候,就會出現下面這種效果,不僅樣式不統一,有的時候,密碼框的上面並不是用戶名,而是其他的內容,也會被強制显示為用戶名:
首先需要解決樣式問題:
#app input:-webkit-autofill { -webkit-text-fill-color: #fff !important; -webkit-box-shadow: none !important; background-color: transparent; background-image: none; transition: background-color 999999s ease-in-out, color 999999s ease-in-out; }
其次,阻止谷歌自帶的記住密碼:
單個el-input獲得焦點時,點擊鍵盤迴車,會觸發路由重定向。
解決方法:@submit.native.preven t阻止表單默認事件
element的日期框添加默認值后,在ie下,默認的清空按鈕無法清空默認日期值:
數據應該是已經清空了,但是DOM沒有刷新,所以需要強制刷新DOM:
<template>
<div>
<el-table-column
v-for="(item, idx) in list"
:key="idx"
v-bind="item" :show-overflow-tooltip="true">
<tHeader
v-if="item.children"
:list="item.children">
</tHeader>
</el-table-column>
</div>
</template>
<script>
export default {
name: 'tHeader',
props: [
'list'
],
methods: {
repairEleSortBug() {
this.list.unshift(this.list.pop());
}
},
created() {
//修復elementUI排序倒置的bug(將數組最後一個放到第一個)
this.repairEleSortBug();
}
};
</script>
在vue中可以通過監聽一個變量的值變化觸發相應事件,但是當需要監聽的變量是個複雜對象時,通常在外出是監聽不到對象裏面值的變化,這時就需要深度監聽:
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※台北網頁設計公司這麼多該如何選擇?
※智慧手機時代的來臨,RWD網頁設計為架站首選
※評比南投搬家公司費用收費行情懶人包大公開
※幫你省時又省力,新北清潔一流服務好口碑
※回頭車貨運收費標準