C++ std::find 搜尋用法與範例

本篇介紹 C++ 的 std::find 搜尋/尋找的用法教學,C++ find 常用於容器裡搜尋,例如:傳統陣列 array 或 vector 等其他容器,
在使用 C++ STL 容器時需要搜尋/尋找就可以使 std::find,學習後可以說是方便許多,C++ 最常用到的就是在 vector 裡 find 搜尋,這邊把常用到的用法與範例紀錄一下。

以下內容將分為這幾部分,

  • 範例1. 在傳統陣列尋找
  • 範例2. 在 C++ STL vector 容器尋找
  • 範例3. 使用 std::find_if 函式來尋找

需要引入的標頭檔<algorithm>

範例1. 在傳統陣列尋找

這邊示範 c++ 使用 std::find 在傳統陣列裡搜尋目標數值,例如我要搜尋整數 3 有沒有在這個陣列裡,

std-find1.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// g++ std-find1.cpp -o a.out
#include <iostream>
#include <algorithm>

using namespace std;

int main() {
int arr[] = {2, 3, 4, 5, 6};

int *p = std::find(arr, arr+4, 3); // find 3
if (p == arr+4) {
cout << "not find\n";
} else {
cout << "found " << *p << "\n";
}

return 0;
}

結果輸出如下,

1
found 3

範例2. 在 C++ STL vector 容器尋找

這邊示範 c++ 使用 std::find 在 std::vector 容器裡搜尋目標數值,使用 std::find 傳入 vector 後,在 std::find 的第一個參數與第二個參數指定搜尋範圍後,第三個參數為欲搜尋的數值,

最後判斷一下,如果迭代到 vector 最後一個元素的話代表沒有搜尋找到該數值,

例如我要搜尋整數 10 有沒有在這個 vector 裡,

std-find2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// g++ std-find2.cpp -o a.out -std=c++11
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
vector<int> v = {2, 4, 6, 8, 10, 12, 14, 16, 18};

vector<int>::iterator it = std::find(v.begin(), v.end(), 10); // find 10
if (it != v.end())
cout << "found " << *it << ", index: " << std::distance(v.begin(), it) << "\n";
else
cout << "not find\n";

return 0;
}

結果輸出如下,

1
found 10, index: 4

範例3. 使用 std::find_if 函式來尋找

這個範例是使用 std::find_if 在 std::vector 容器搜尋目標數值,功能跟 std::find 很像所以這邊也介紹一下,差別在 std::find_if 的第三的參數是放入謂詞(pred),

例如我要搜尋整數 5 有沒有在這個 vector 裡,這裡我們示範自己寫的 equal_5 謂詞,

std-find3.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// g++ std-find3.cpp -o a.out -std=c++11
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

template<typename T>
bool smallthan_5(T value) {
return value < 5;
}

template<typename T>
bool equal_5(T value) {
return value == 5;
}

int main() {
vector<int> v;
v.push_back(2);
v.push_back(4);
v.push_back(3);
v.push_back(5);
v.push_back(6);

vector<int>::iterator it = find_if(v.begin(), v.end(), equal_5<int>);
if (it != v.end())
cout << "found " << *it << endl;
else
cout << "not find\n";

return 0;
}

結果輸出如下,

1
found 5

不想自己寫謂詞,你也可以使用內建的 equal_to<type>() 謂詞像這樣寫,

1
2
3
#include <functional>
using std::placeholders::_1;
vector<int>::iterator it = find_if(v.begin(), v.end(), bind(equal_to<>(), _1, 5));

或這樣寫,

1
vector<int>::iterator it = find_if(v.begin(), v.end(), bind2nd(equal_to<int>(), 5));

你還可以使用 lambda 表達式像這樣寫,

1
vector<int>::iterator it = find_if(v.begin(), v.end(), [](int value) { return value == 5; });

以上就是 C++ std::find 搜尋用法與範例介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其他參考
[1] std::find, std::find_if, std::find_if_not - cppreference.com
https://en.cppreference.com/w/cpp/algorithm/find
[2] find - C++ Reference
http://www.cplusplus.com/reference/algorithm/find/
[3] std::find in C++ - GeeksforGeeks
https://www.geeksforgeeks.org/std-find-in-cpp/
[4] C++ find()函数用法(一般用于vector的查找)
https://blog.csdn.net/zhangweijiqn/article/details/9107571

其它相關文章推薦
C/C++ 新手入門教學懶人包
std::thread 用法與範例
std::deque 用法與範例
std::mutex 用法與範例
std::unordered_map 用法與範例
std::sort 用法與範例
std::random_shuffle 產生不重複的隨機亂數
std::shared_ptr 用法與範例
std::async 用法與範例

std::mutex 用法與範例

本篇介紹 C++ 的 std::mutex 的用法教學,並提供一些入門的 std::mutex C++ 範例程式碼,std::mutex 算是多執行緒中常用到的基本功能,mutex 用來上鎖一段多執行緒會交互存取的程式區塊,確保同一時間內只有一個執行緒能夠存取這段程式區塊,避免程式發生不預期的意外狀況,這裡把常用到的用法與範例在這邊紀錄一下,建議閱讀以下文章前需先對建立 std::thread 多執行緒有一定程度的熟悉。

std::mutex 通常不單獨使用而是搭配使用,例如:std::lock_guard、std::unique_lock、std::scoped_lock(C++17),其中最常搭配 std::lock_guard 一起使用。

需要引入的標頭檔<mutex>

範例. 多執行緒呼叫同一個函式(沒有 mutex 鎖)

以下範例是多執行緒最基本也是最常遇見的情形,main 建立了兩個執行緒並且會同時存取 print 函式的資源,
print 會將帶入的參數 c 字元印 n 次,且每次印完會將 g_count 全域變數的次數加1,print 函式最後再將這 g_count 全域變數印出來。
第一個執行緒為 t1 執行緒,會印出 10 個 A,
第二個執行緒為 t2 執行緒,會印出 5 個 B,
如果我們今天想讓 print 某一時間只能某個執行緒來執行存取的話,
我們來看看如果沒有 mutex 的保護臨界區,這個程式的輸出會是怎樣。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <thread>

using namespace std;

int g_count = 0;

int print(int n, char c) {
for (int i = 0; i < n; ++i) {
std::cout << c;
g_count++;
}
std::cout << '\n';

std::cout << "count=" << g_count << std::endl;
}

int main() {
std::thread t1(print, 10, 'A');
std::thread t2(print, 5, 'B');
t1.join();
t2.join();

return 0;
}

如果沒上鎖的話,可能造成不預期的輸出,如下count=5A所示,t2 執行緒的 g_count 還沒來得及印完\n,另一個執行緒 t1 已經開始搶著印了。
另外補充一下,t1 與 t2 誰先執行並沒有一定誰先誰後,每次執行的結果都有可能不同。

1
2
3
4
BBBBB
count=5A
AAAAAAAAA
count=15

範例. 多執行緒呼叫同一個函式(有 mutex 鎖)

根據上面的範例進行延伸修改,因為這兩個執行緒都共同存取 g_count 這個全域變數,如果要讓執行結果符合預期的話,這邊需要上鎖,
已確保同一時間內只有一個執行緒能夠存取這個 g_count 全域變數,當有執行緒占用時,其它執行緒要存取該資源時,就會被擋住,
直到該資源被執行緒釋放後,才能被其它執行緒存取。

這裡我們在 print 函式裡使用 g_mutex.lock() 手動上鎖,
並且在 print 函式最後尾巴使用 g_mutex.unlock() 手動解鎖,

std-mutex.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// g++ std-mutex.cpp -o a.out -std=c++11 -pthread
#include <iostream>
#include <thread>
#include <mutex>

using namespace std;

std::mutex g_mutex;
int g_count = 0;

int print(int n, char c) {
// critical section (exclusive access to std::cout signaled by locking mtx):
g_mutex.lock();
for (int i = 0; i < n; ++i) {
std::cout << c;
g_count++;
}
std::cout << '\n';

std::cout << "count=" << g_count << std::endl;
g_mutex.unlock();
}

int main() {
std::thread t1(print, 10, 'A');
std::thread t2(print, 5, 'B');
t1.join();
t2.join();

return 0;
}

輸出如下,這樣就達成我們的目的,符合我們預期的輸出了。
下個範例會介紹更智慧的寫法。

1
2
3
4
AAAAAAAAAA
count=10
BBBBB
count=15

範例. 使用 lock_guard 來上鎖與解鎖

直接使用 std::mutex 的成員函式 lock/unlock 來上鎖是可以的,只是要注意 lock 要有對應的 unlock ,一旦沒有解鎖到程式很可能就會發生死鎖,
那有沒有比較智慧的寫法來避免這種忘記解鎖而照成死鎖的問題發生呢?
有的!答案就是配合 std::lock_guard 使用,學會用 std::lock_guard 就可以避免手動上鎖解鎖,進而減少在寫程式上出現死鎖的機會,
以下就來介紹 mutex 配合 lock_guard 來上鎖與解鎖,
根據前一個範例進行修改,將原本使用 g_mutex 上鎖與解鎖的動作,換成了 lock_guard,如下範例所示,
在 lock_guard 建構時帶入一個 mutex,就會自動將其 mutex 上鎖,而在 lock_guard 解構時會對其 mutex 解鎖,
簡單說就是「lock_guard 建構時對 mutex 上鎖,解構時對 mutex 解鎖」,
lock_guard 利用生命週期這概念來進行上鎖與解鎖,lock_guard 本身並不管理 mutex 的生命週期,也就是 lock_guard 生命週期結束不代表 mutex 生命週期也結束,
以下面這個例子為例,在進入 print 後將 g_mutex 帶入 lock_guard 建構時上鎖,之後離開 print 函式時,lock_guard 生命週期也隨之結束,lock_guard 進行解構時對 g_mutex 解鎖
lock_guard 詳細介紹與實作原理請看這篇。

std-mutex2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// g++ std-mutex2.cpp -o a.out -std=c++11 -pthread
#include <iostream>
#include <thread>
#include <mutex>

using namespace std;

std::mutex g_mutex;
int g_count = 0;

int print(int n, char c) {
// critical section (exclusive access to std::cout signaled by locking mtx):
std::lock_guard<std::mutex> lock(g_mutex);
for (int i = 0; i < n; ++i) {
std::cout << c;
g_count++;
}
std::cout << '\n';

std::cout << "count=" << g_count << std::endl;
}

int main() {
std::thread t1(print, 10, 'A');
std::thread t2(print, 5, 'B');
t1.join();
t2.join();

return 0;
}

輸出結果如下,效果跟前一個範例一樣

1
2
3
4
AAAAAAAAAA
count=10
BBBBB
count=15

下一篇介紹 std::condition_variable 的用法,以及 std::unique_lock 怎麼跟 condition_variable 搭配使用
同時也介紹怎麼跟 queue 的結合應用,也是設計模式中常見的生產者消費者模式。

參考
[1] std::mutex - cppreference.com
https://en.cppreference.com/w/cpp/thread/mutex
[2] mutex - C++ Reference
http://www.cplusplus.com/reference/mutex/mutex/
[3] C++11 併發指南三(std::mutex 詳解) - IT閱讀
https://www.itread01.com/content/1546128929.html
完整且複雜的一篇

其它相關文章推薦
C/C++ 新手入門教學懶人包
std::mutex 怎麼實作的?
std::thread 用法與範例
std::condition_variable 用法與範例

C++ std::thread 建立多執行緒用法與範例

本篇介紹 C++ 的 std::thread 建立多執行緒的用法教學,並提供一些入門的 std::thread C++ 範例程式碼,std::thread 建立執行緒算是多執行緒的基本必學,這邊把常用到的用法與範例紀錄一下。

在c++11 thread 出來之前, 跨平台開發執行緒程式一直需要依賴平台的 api,例如 Windows 要呼叫 CreateThread, Unix-like 使用 pthread_create 等等情形。c++11 thread 出來之後最大的好處就是開發者只需寫一種 thread,到各平台去編譯就行了,這當然還要編譯器支援c++11。

需要引入的標頭檔<thread>

接下來就介紹簡單的 c++ thread 寫法,內容分為以下幾部分:

  • 基本 std::thread 的用法
  • std::thread 常用的成員函式
  • 範例1. 建立新 thread 來執行一個函式,且帶入有/無參數
  • 範例2. 建立新 thread 來執行一個類別函式
  • 範例3. 建立新 thread 來執行 lambda expression
  • 範例4. join 等待 thread 執行結束
  • 範例5. detach 不等待 thread 執行結束
  • std::thread 用陣列建立多個 thread
  • std::thread 用 vector 建立多個 thread
  • std::thread 參數傳遞使用傳參考的方法

基本 std::thread 的用法

c++ 最簡單的 std::thread 範例如下所示,呼叫 thread 建構子時會立即同時地開始執行這個新建立的執行緒,之後 main() 的主執行緒也會繼續執行,基本上這就是一個基本的建立執行緒的功能了。詳細說明請看後面的範例。

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <thread>

void myfunc() {
std::cout << "myfunc\n";
// do something ...
}

int main() {
std::thread t1(myfunc);
t1.join();
return 0;
}

std::thread 常用的成員函式

以下為 c++ std::thread 常用的成員函式,
get_id(): 取得目前的執行緒的 id,回傳一個為 std::thread::id 的類型。
joinable(): 檢查是否可join。
join(): 等待執行緒完成。
detach(): 與該執行緒分離,一旦該執行緒執行完後它所分配的資源會被釋放。
native_handle(): 取得平台原生的native handle (例如Win32的Handle, unix的pthread_t)。

其他相關的常用函式有,
sleep_for(): 停止目前執行緒一段指定的時間。
yield(): 暫時放棄CPU一段時間,讓給其它執行緒。

範例1. 建立新 thread 來執行一個函式,且帶入有/無參數

以下例子為建立新 c++ thread 來執行一個函式,其中 t1 是呼叫無參數的 foo() 函式,而 t2 執行緒是呼叫 bar() 有參數的函式。

std-thread1.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// g++ std-thread1.cpp -o a.out -std=c++11 -pthread
#include <iostream>
#include <thread>

void foo() {
std::cout << "foo\n";
}

void bar(int x) {
std::cout << "bar\n";
}

int main() {
std::thread t1(foo); // 建立一個新執行緒且執行 foo 函式
std::thread t2(bar, 0); // 建立一個新執行緒且執行 bar 函式
std::cout << "main, foo and bar now execute concurrently...\n"; // synchronize threads

std::cout << "sleep 1s\n";
std::this_thread::sleep_for(std::chrono::seconds(1));

std::cout << "join t1\n";
t1.join(); // 等待 t1 執行緒結束
std::cout << "join t2\n";
t2.join(); // 等待 t2 執行緒結束

std::cout << "foo and bar completed.\n";

return 0;
}

輸出

1
2
3
4
5
6
7
main, foo and bar now execute concurrently...
foo
bar
sleep 1s
join t1
join t2
foo and bar completed.

注意!在多執行緒程式中常常會互相存取某段程式碼、某個函式、某個變數,需要對這些程式碼進行上鎖,以確保同一時間只有某一個執行緒能進行存取。

範例2. 建立新 thread 來執行一個類別函式

c++ std::thread 的建構子可以傳入 class 類別的函式,如下範例所示,
AA::start 分別建立 t1、t2 兩個執行緒,而 t1 建構子帶入 AA::a1 類別函式,AA::a1 前面記得要加上&,第二參數代表的是哪個類別,之後的參數為帶入類別函式的參數就像 t2 這樣。

std-thread2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// g++ std-thread2.cpp -o a.out -std=c++11 -pthread
#include <iostream>
#include <thread>

class AA {
public:
void a1() {
std::cout << "a1\n";
}

void a2(int n) {
std::cout << "a2 " << n << "\n";
}

void start() {
std::thread t1(&AA::a1, this);
std::thread t2(&AA::a2, this, 10);

t1.join();
t2.join();
}
};

int main() {
AA a;
a.start();

return 0;
}

輸出

1
2
a1
a2 10

範例3. 建立新 thread 來執行 lambda expression

std::thread 的建構子也可以傳入來 lambda expression,如下範例所示:

1
2
3
4
auto f = [](int n) {
// Do Something
};
std::thread t1(f, 3);

也可以寫成

1
2
3
std::thread t1([](int n) {
// Do Something
};, 3);

範例4. join 等待 thread 執行結束

在 main 主執行緒建立 t1 執行緒後,主執行緒便繼續往下執行,
如果主執行緒需要等 t1 執行完畢後才能繼續執行的話就需要使用 join,
即等待 t1 執行緒執行完 foo 後主執行緒才能繼續執行,
否則主執行緒會一直卡(blocking)在 join 這一行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <thread>
#include <chrono>

void foo() {
this_thread::sleep_for(chrono::milliseconds(200));
cout<<"foo";
}

int main() {
std::thread t1(foo);
cout<<"main 1";
t1.join();
cout<<"main 2";
return 0;
}

範例5. detach 不等待 thread 執行結束

承上例子,如果主執行緒不想等或是可以不用等待 t1 執行緒的話,
就可以使用 detach 來讓 t1 執行緒分離,接著主執行緒就可以繼續執行,t1執行緒也在繼續執行,
在整個程式結束前最好養成好習慣確保所有子執行緒都已執行完畢,
因為在 linux 系統如果主執行緒執行結束還有子執行緒在執行的話會跳出個錯誤訊息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <thread>
#include <chrono>

void foo() {
this_thread::sleep_for(chrono::milliseconds(200));
cout<<"foo";
}

int main() {
std::thread t1(foo);
cout<<"main 1";
t1.detach();
cout<<"main 2";
return 0;
}

std::thread 用陣列建立多個 thread

這邊示範建立多個執行緒,這個例子是建立 3 個執行緒,用陣列的方式來存放 std::thread,寫法如下,

std-thread-array.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// g++ std-thread-array.cpp -o a.out -std=c++11 -pthread
#include <iostream>
#include <thread>

void foo(int n) {
std::cout << "foo() " << n << "\n";
}

int main() {
std::thread threads[3];

for (int i = 0; i < 3; i++) {
threads[i] = std::thread(foo, i);
}

for (int i = 0; i < 3; i++) {
threads[i].join();
}

std::cout << "main() exit.\n";

return 0;
}

結果輸出如下,

1
2
3
4
foo() 1
foo() 0
foo() 2
main() exit.

std::thread 用 vector 建立多個 thread

這邊示範建立多個執行緒,與上述例子不同,這是我們改用 vector 來存放 std::thread,寫法如下,

std-thread-vector.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// g++ std-thread-vector.cpp -o a.out -std=c++11 -pthread
#include <iostream>
#include <thread>
#include <vector>

void foo(int n) {
std::cout << "foo() " << n << std::endl;
}

int main() {
std::vector<std::thread> threads;

for (int i = 0; i < 3; i++) {
threads.push_back(std::thread(foo, i));
}

for (int i = 0; i < 3; i++) {
threads[i].join();
}

std::cout << "main() exit.\n";

return 0;
}

結果輸出如下,

1
2
3
4
foo() 0
foo() 2
foo() 1
main() exit.

std::thread 參數傳遞使用傳參考的方法

如果我今天有個 myfunc 參數傳遞方式為傳參考,內容如下,

1
2
3
4
void myfunc(int& n) {
std::cout << "myfunc n=" << n << "\n";
n+=10;
}

我希望透過建立另外一個執行緒去執行 myfunc,之後我要取得這個 myfunc 的運算結果,那我建立執行緒時如果寫 std::thread t1(myfunc, n); 這樣的話馬上編譯會出現錯誤,為什麼會這樣呢?原因是因為在 std::thread 的參數傳遞方式為傳值,要傳參考的話需要透過 std::ref 來輔助達成,所以程式就會寫成這樣,myfunc 與 myfunc2 的參數傳遞方式不同,可以看看這兩者之間的差異,

std-thread3.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// g++ std-thread3.cpp -o a.out -std=c++11 -pthread
#include <iostream>
#include <thread>

void myfunc(int& n) {
std::cout << "myfunc n=" << n << "\n";
n+=10;
}

void myfunc2(int n) {
std::cout << "myfunc n=" << n << "\n";
n+=10;
}

int main() {
int n1 = 5;
std::thread t1(myfunc, std::ref(n1));
t1.join();
std::cout << "main n1=" << n1 << "\n";

int n2 = 5;
std::thread t2(myfunc2, n2);
t2.join();
std::cout << "main n2=" << n2 << "\n";

return 0;
}

結果輸出如下,

1
2
3
4
myfunc n=5
main n1=15
myfunc n=5
main n2=5

下一篇文章會告訴你在 多執行緒程式中使用 std::mutex 對程式碼進行上鎖的用法與範例。

其他參考
[1] thread - C++ Reference
http://www.cplusplus.com/reference/thread/thread/
[2] std::thread - cppreference.com
https://en.cppreference.com/w/cpp/thread/thread
[3] Multithreading in C++ - GeeksforGeeks
https://www.geeksforgeeks.org/multithreading-in-cpp/
[4] C++ std::thread | 菜鳥教程
https://www.runoob.com/w3cnote/cpp-std-thread.html
[5] C++ 的多執行序程式開發 Thread:基本使用 – Heresy’s Space
https://kheresy.wordpress.com/2012/07/06/multi-thread-programming-in-c-thread-p1/

相關文章
C/C++ 新手入門教學懶人包
std::thread 怎麼實作的?
如何取得 C++11 thread id
std::this_thread::sleep_for 用法與範例
std::mutex 用法與範例
std::condition_variable 用法與範例

Python 讀取 yaml 檔案

本篇介紹如何用 Python 讀取 read yaml 檔案,yaml 檔案格式是常用設定檔格式,以下將示範如何用 python 搭配 yaml 套件的 yaml.load() 來 read 讀取 yaml 檔案。

PyPI:https://pypi.org/project/PyYAML/
Github:https://github.com/yaml/pyyaml/

安裝方式

透過 pip 安裝 pyyaml,注意在程式裡是 import yaml

1
pip install pyyaml

讀取 yaml 檔案

假設要讀取的 data.yaml 內容長這樣,

data.yaml
1
2
3
name: Jack
age: 20
sex: Male

以下範例使用 with open 的寫法來開檔,之後在使用 yaml.load() 取得 data 這個字典 dict,
之後就可以使用該字典 dict 來取得想索取的設定值了,
程式碼如下:

python3-yaml-read.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import yaml

with open('data.yaml', 'r') as f:
data = yaml.load(f)

print(yaml.dump(data))
print('---')
print(type(data))
print(data)
print('---')
print(data['name'])
print(data['age'])

輸出結果如下,

1
2
3
4
5
6
7
8
{age: 20, name: Jack, sex: Male}

---
<class 'dict'>
{'age': 20, 'sex': 'Male', 'name': 'Jack'}
---
Jack
20

下一篇介紹 寫入 yaml 檔案

其他參考
PyYAML Documentation
https://pyyaml.org/wiki/PyYAMLDocumentation
python yaml用法详解_Python_Easton Liu的博客-CSDN博客
https://blog.csdn.net/lmj19851117/article/details/78843486
python笔记14-读取yaml配置文件(pyyaml) - 上海-悠悠 - 博客园
https://www.cnblogs.com/yoyoketang/p/8874392.html
Python读取Yaml文件 - ListenWind - 博客园
https://www.cnblogs.com/ListenWind/p/4518198.html
使用 python 讀取 yaml 檔案 - 亂點技能的跨界人生 - Medium
https://medium.com/bryanyang0528/%E4%BD%BF%E7%94%A8-python-%E8%AE%80%E5%8F%96-yaml-%E6%AA%94%E6%A1%88-d3f413d7dd6

其它相關文章推薦
如果你想學習 Python 相關技術,可以參考看看下面的文章,
Python 新手入門教學懶人包
Python 寫檔,寫入 txt 文字檔
Python 讀取 csv 檔案
Python 寫入 csv 檔案
Python 字串分割 split
Python 取代字元或取代字串 replace
Python 讓程式 sleep 延遲暫停時間
Python 產生 random 隨機不重複的數字 list
Python PyAutoGUI 使用教學
Python OpenCV resize 圖片縮放

Python 寫入 csv 檔案

本篇介紹如何用 python write csv 檔案,csv 檔案格式是常用格式,以下將示範如何用 python 的內建 csv 模組的 csv.writer 來寫入 csv 檔案。

  • Python 寫入 csv 的基本用法
  • 把 list 裡的資料寫入 csv
  • 把 2 維 list 裡的資料寫入 csv
  • 把 dict 裡的資料寫入 csv
  • 用 numpy 套件寫入 csv
  • 用 pandas 套件寫入 csv

    Python 寫入 csv 的基本用法

    這邊介紹 Python 使用內建的 csv 模組寫入 csv 檔的基本用法,以下範例是使用 with open 的寫法來開檔,之後在使用 csv.writer 取得 writer,
    之後可以呼叫 writerow 將每行的數值寫入,
    記得要設定 newline 的值,否則 Python 寫入輸出的 csv 檔會多個空行。

Python write csv 用法範例如下,

python3-csv-write2.py
1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import csv

path = 'output_data.csv'
with open(path, 'w', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(['No', 'Name', 'Score'])
writer.writerow([1, 'Tom', 87.3])
writer.writerow([2, 'Mary', 76.4])
writer.writerow([3, 'Mark', 65.5])

輸出結果如下:

1
2
3
4
No,Name,Score
1,Tom,87.3
2,Mary,76.4
3,Mark,65.5

把 list 裡的資料寫入 csv

假如我們要寫入的資料是存放在 list 的話可以這樣子寫,

python3-csv-write3.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import csv

headers = ['No', 'Name', 'Score']
ids = [1, 2, 3]
names = ['Tom', 'Mary', 'Mark']
scores = [87.3, 76.4, 65.5]

path = 'output_data.csv'
with open(path, 'w', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(headers)
for i in range(len(ids)):
writer.writerow([ids[i], names[i], scores[i]])

輸出結果同上。

把 2 維 list 裡的資料寫入 csv

假如我們要寫入的資料是 2 維 list 的話可以這樣子寫,

python3-csv-write4.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import csv

my2dlist = [
['No', 'Name', 'Score'],
[1, 'Tom', 87.3],
[2, 'Mary', 76.4],
[3, 'Mark', 65.5]
]

path = 'output_data.csv'
with open(path, 'w', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerows(my2dlist)

輸出結果同上。

把 dict 裡的資料寫入 csv

假如我們要寫入的資料是存放在 dict 的話可以這樣子寫,

python3-csv-write5.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import csv

mydict1 = {'No':1, 'Name':'Tom', 'Score':87.3}
mydict2 = {'No':2, 'Name':'Mary', 'Score':76.4}
mydict3 = {'No':3, 'Name':'Mark', 'Score':65.5}

path = 'output_data.csv'
with open(path, 'w', newline='') as csvfile:
writer = csv.writer(csvfile)

headers = ['No', 'Name', 'Score']
writer = csv.DictWriter(csvfile, fieldnames=headers)
writer.writeheader()
writer.writerow(mydict1)
writer.writerow(mydict2)
writer.writerow(mydict3)

寫得更好的點話,可以把這 3 個 dict 放在 list 裡,

python3-csv-write6.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import csv

mylist = [
{'No':1, 'Name':'Tom', 'Score':87.3}, # dict
{'No':2, 'Name':'Mary', 'Score':76.4}, # dict
{'No':3, 'Name':'Mark', 'Score':65.5} # dict
]

path = 'output_data.csv'
with open(path, 'w', newline='') as csvfile:
writer = csv.writer(csvfile)

headers = ['No', 'Name', 'Score']
writer = csv.DictWriter(csvfile, fieldnames=headers)
writer.writeheader()
for i in range(len(mylist)):
writer.writerow(mylist[i])

輸出結果同上。

用 numpy 套件寫入 csv

前面的方法都是使用內建的 csv 模組,這邊要介紹使用 numpy 模組來寫入 csv 檔,
以下用 np.savetxt() 將 2 維的 list 寫入 csv,

python3-csv-write7.py
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import numpy as np

my2dlist = [
['No', 'Name', 'Score'],
[1, 'Tom', 87.3],
[2, 'Mary', 76.4],
[3, 'Mark', 65.5]
]

path = 'output_data.csv'
np.savetxt(path, my2dlist, delimiter=',', fmt='%s')

輸出結果同上。

假如是要將 numpy array 寫入 csv 檔的話,就像這樣寫,

python3-csv-write8.py
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import numpy as np

my2dlist = np.asarray([
['No', 'Name', 'Score'],
[1, 'Tom', 87.3],
[2, 'Mary', 76.4],
[3, 'Mark', 65.5]
])

path = 'output_data.csv'
np.savetxt(path, my2dlist, delimiter=',', fmt='%s')

輸出結果同上。

用 pandas 套件將 list 寫入 csv

這邊要介紹使用 pandas 模組來將 2 維的 list 寫入 csv 檔,

python3-csv-write9.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import pandas as pd

headers = ['No', 'Name', 'Score']
my2dlist = [
[1, 'Tom', 87.3],
[2, 'Mary', 76.4],
[3, 'Mark', 65.5]
]

path = 'output_data.csv'
df = pd.DataFrame(columns=headers, data=my2dlist)
df.to_csv(path) # index = True

輸出的結果如下,發現左邊有多一欄 index 索引欄位,

1
2
3
4
,Name,No,Score
0,Tom,1,87.3
1,Mary,2,76.4
2,Mark,3,65.5

如果要去除左邊的 index 索引欄位的話在 to_csv() 加入 index=False 即可,

1
df.to_csv(path, index=False)

輸出的結果如下,就沒有左邊的 index 那一欄,這樣就跟原本的輸出一樣了,

1
2
3
4
No,Name,Score
1,Tom,87.3
2,Mary,76.4
3,Mark,65.5

用 pandas 套件將 dict 寫入 csv

這邊要介紹使用 pandas 模組來將 dict 寫入 csv 檔,

python3-csv-write10.py
1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import pandas as pd

ids = [1, 2, 3]
names = ['Tom', 'Mary', 'Mark']
scores = [87.3, 76.4, 65.5]
mydict = {'No': ids, 'Name': names, 'Score': scores}

path = 'output_data.csv'
df = pd.DataFrame(mydict)
df.to_csv(path, index=False)

結果跟原本的差不多,只是欄位順序沒有按照我們放入的順序而已,

1
2
3
4
Name,No,Score
Tom,1,87.3
Mary,2,76.4
Mark,3,65.5

以上就是 Python 寫入 csv 檔案的介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它參考
csv — CSV File Reading and Writing — Python 3 documentation
https://docs.python.org/3/library/csv.html#csv.writer

相關主題
Python 讀取 csv 檔案
Python 讀檔,讀取 txt 文字檔
Python 讀寫檔案
Python 使用 numpy 讀取 csv 資料再畫圖
Python numpy 寫入 csv

Python replace 取代字串用法與範例

本篇 ShengYu 介紹 Python replace 取代字串的用法與範例,str.replace 就是將字串中的舊字串取代成新字串,str.replace 是不會改變原本字串內容,而是會另外回傳新的結果字串。

以下 Python replace 取代字串用法與範例將分為這幾部份,

  • Python replace 語法參數
  • Python replace 基本使用範例
  • Python replace 單次與取代與多次取代

那我們開始吧!

Python replace 語法參數

Python str.replace 語法參數如下,

1
str.replace(old, new[, max])

參數說明
old:將被取代的子字串
new:用於取代 old 子字串的新字串
max:可選參數,取代字串不超過 max 次

回傳值
回傳取代後新的結果字串。

Python replace 基本使用範例

Python 的 str replace 用處在於把字串中的原本字串(old)取代成新的字串(new),
str.replace(old, new) 使用語法為把第一個參數(old)取代為第二個參數(new),
以下範例是在 Python 3 環境下測試過,也可以在 Python 2.7 環境下執行,程式碼如下:

python3-replace.py
1
2
3
4
5
6
7
8
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

str1 = 'abc,de,f'
print('str: ' + str1)
print('str: ' + str1.replace('de', '123'))
str2 = str1.replace('b', '45')
print('str: ' + str2)

輸出結果如下:

1
2
3
str: abc,de,f
str: abc,123,f
str: a45c,de,f

Python replace 單次與取代與多次取代

如果要限定次數取代的話,可以在 replace(old, new, max) 的第三個參數指定次數,不帶入第三個參數的話,預設是無限次。
程式碼如下:

python3-replace2.py
1
2
3
4
5
6
7
8
9
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

str1 = 'abcdef,abcde,abcde'
print('str: ' + str1)
str2 = str1.replace('cd', '34')
print('str: ' + str2)
str3 = str2.replace('ab', '12', 2)
print('str: ' + str3)

輸出結果如下:

1
2
3
str: abcdef,abcde,abcde
str: ab34ef,ab34e,ab34e
str: 1234ef,1234e,ab34e

下一篇介紹 strip 去除空白與去除特殊字元

以上就是 Python replace 取代字串用法與範例介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它相關文章推薦
如果你想學習 Python 相關技術,可以參考看看下面的文章,
Python str 字串用法與範例
Python 新手入門教學懶人包
Python 字串分割 split
Python 連接字串 join
Python 去除空白與去除特殊字元 strip
Python 取出檔案名稱 basename
Python 取出目錄的路徑 dirname

Python strip 去除空白與去除特殊字元用法與範例

本篇 ShengYu 介紹 Python strip 去除空白與去除特殊字元的用法與範例。
以下範例是在 Python 3 環境下測試過。

Python strip 去除空白

Python strip 的功用是用來去除一些多餘的字串,例如字串頭的空白或字串尾的空白,
實際上只要是字串頭部與字串尾部有包含空白的都會去除,字串中段的部份並不會去除。

Python strip 的用法如下,

python-os-path-basename.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

str1 = ' 123 '
str2 = str1.strip()
print(str2 + ' len:' + str(len(str2)))
str3 = ' 123'
str4 = str3.strip()
print(str4 + ' len:' + str(len(str4)))
str5 = '123 '
str6 = str5.strip()
print(str6 + ' len:' + str(len(str6)))
str7 = '123 5 7 9 '
str8 = str7.strip()
print(str8 + ' len:' + str(len(str8)))

輸出結果如下:

1
2
3
4
123 len:3
123 len:3
123 len:3
123 5 7 9 len:9

下一篇介紹 join 連接字串的用法

參考
Python strip()方法 | 菜鸟教程
https://www.runoob.com/python/att-string-strip.html
Python3 strip()方法 | 菜鸟教程
https://www.runoob.com/python3/python3-string-strip.html

其它相關文章推薦
如果你想學習 Python 相關技術,可以參考看看下面的文章,
Python str 字串用法與範例
Python 新手入門教學懶人包
Python 字串分割 split
Python 連接字串 join
Python 取代字元或取代字串 replace
Python 取出檔案名稱 basename
Python 取出目錄的路徑 dirname

Python join 連接字串用法與範例

本篇 ShengYu 介紹 Python join 連接字串的用法與範例。
以下範例是在 Python 3 環境下測試過。

使用範例

Python 中的 join 是用指定的符號來連接多個字串,跟 split 相反,
split 是根據指定的分隔符號去分割字串,
join 是根據指定的連結符號去連接字串,

程式碼如下:

python-os-path-basename.py
1
2
3
4
5
6
7
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

str1 = '-'
list1 = ['a', 'b', 'c']
str2 = str1.join(list1)
print(str2)

輸出結果如下:

1
a-b-c

下一篇介紹 split 字串分割的用法

參考
Python join()方法 | 菜鸟教程
https://www.runoob.com/python/att-string-join.html
Python3 join()方法 | 菜鸟教程
https://www.runoob.com/python3/python3-string-join.html

其它相關文章推薦
如果你想學習 Python 相關技術,可以參考看看下面的文章,
Python str 字串用法與範例
Python 新手入門教學懶人包
Python 字串分割 split
Python 去除空白與去除特殊字元 strip
Python 取代字元或取代字串 replace
Python 取出檔案名稱 basename
Python 取出目錄的路徑 dirname

Python split 字串分割用法與範例

本篇 ShengYu 介紹 Python split 字串分割的用法與範例,在字串處理中常常會需要將字串根據某個符號來切割,例如:空白,逗號,藉此區分出資料的欄位,常見於讀取文字檔或讀取 csv 的欄位切割處理,Python split 字串分割算是字串處理中最常用到的功能,

以下的 Python split 字串分割用法與範例將分為這幾部分,

  • Python split 字串切割使用範例
  • split() 指定 , 逗號為分隔符號
  • split() 指定了不存在的分隔符號會怎樣?
  • split() 指定要切割幾次

那我們開始吧!
以下範例是在 Python 3 環境下測試過。

Python split 字串切割使用範例

Python split 的用處在於把字串透過指定的分隔符號對字串進行分割,分割後的字串會儲存在一個串列 list,
split() 第一個參數為指定的分隔符號,可以是空白,換行(\n),tab(\t), 逗號(,) 或其他字元等等,
split() 不給入參數的話,預設會以空白作為分隔符號做切割,

以下示範空白為分隔符號:

python-split.py
1
2
3
4
5
6
7
8
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

str1 = '1 2 3'
print(str1)
str2 = str1.split(' ')
print(str2)
print(str1.split())

輸出結果如下:

1
2
3
1 2 3
['1', '2', '3']
['1', '2', '3']

split 回傳的串列可以透過 len() 來知道這個串列有幾個元素,

python-split2.py
1
2
3
4
5
6
7
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

str1 = '1 2 3'
str2 = str1.split(' ')
print(str2)
print(len(str2))

len() 計算出的結果如下,

1
2
['1', '2', '3']
3

split() 指定 , 逗號為分隔符號

以下介紹 Python split() 指定 , 逗號為分隔符號的範例,
程式碼如下:

python-split3.py
1
2
3
4
5
6
7
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

str1 = '4,5,6'
print(str1)
str2 = str1.split(',')
print(str2)

輸出結果如下:

1
2
4,5,6
['4', '5', '6']

Python split() 指定 , 為分隔符號的話,原字串如果有空白的話不會幫你去除空白,

python-split4.py
1
2
3
4
5
6
7
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

str1 = '4, 5, 6'
print(str1)
str2 = str1.split(',')
print(str2)

輸出:

1
2
4, 5, 6
['4', ' 5', ' 6']

從上面輸出看得出來切割的結果有包含空白,如果想要去除空白的話可使用 strip 來將這些多餘的空白去除。

split() 指定了不存在的分隔符號會怎樣?

Python 如果 split() 指定了不存在的分隔符號的話會回傳長度為 1 的 list,回傳的這個 list 第一個元素即為原本的字串。

python-split5.py
1
2
3
4
5
6
7
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

str1 = '7,8,9'
print(str1)
str2 = str1.split(' ')
print(str2)

輸出:

1
2
7,8,9
['7,8,9']

split() 指定要切割幾次

Python split() 可以指定要切割幾次,在第二個參數帶入切割次數即可,以下示範指定切割 2 次,

python-split5.py
1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

str1 = 'hello world 1 2 3 4 5'
print(str1)
str2 = str1.split(' ', 2)
print(str2)
print(str2[0])
print(str2[1])
print(str2[2])

輸出:

1
2
3
4
5
hello world 1 2 3 4 5
['hello', 'world', '1 2 3 4 5']
hello
world
1 2 3 4 5

下一篇介紹 replace 取代字元或取代字串

其他參考
Python String split() Method
https://www.w3schools.com/python/ref_string_split.asp
Python String | split() - GeeksforGeeks
https://www.geeksforgeeks.org/python-string-split/

其它相關文章推薦
如果你想學習 Python 相關技術,可以參考看看下面的文章,
Python str 字串用法與範例
Python 新手入門教學懶人包
Python 連接字串 join
Python 去除空白與去除特殊字元 strip
Python 取代字元或取代字串 replace
Python 取出檔案名稱 basename
Python 取出目錄的路徑 dirname

Android開發問題is not accessible for the namespace

https://groups.google.com/g/android-ndk/c/NEJmlH8nOj4?pli=1
看到這篇討論覺得很有趣,就順便來關注一下這是怎樣的一個問題,

1
2
3
4
5
load library failed log like these:

needed or dlopened by "/system/lib/libnativeloader.so" is not accessible for the namespace:
[name="classloader-namespace", ld_library_paths="", default_library_paths="",
permitted_paths="/data:/mnt/expand"]

貌似在說明在新版的Android不支援非系統的 so 放在 /system/ 下,要放在 default_library_pathspermitted_paths 規定的路徑才能被 load 的起來,

在 android 原始碼中搜尋 is not accessible for the namespace 字樣
結果在 /bionic/linker.cpp 中有加載庫的函數
參考 https://blog.csdn.net/u012459903/article/details/100731487

參考
Namespaces for Native Libraries | Android Open Source Project
https://source.android.com/devices/tech/config/namespaces_libraries#adding-additional-native-libraries
Linker Namespace | Android Open Source Project
https://source.android.com/devices/architecture/vndk/linker-namespace
Enabling the VNDK | Android Open Source Project
https://source.android.com/devices/architecture/vndk/enabling

Android 7.0 行为变更 - NDK 应用链接至平台库 Android Developers
https://developer.android.com/about/versions/nougat/android-7.0-changes?hl=zh-cn#ndk

第三方app加载系统/system/lib下的库–is not accessible for the namespace_Canok-CSDN博客
https://blog.csdn.net/u012459903/article/details/100731487

android N : UnsatisfiedLinkError 只能访问设置为公用库的so库- 鸭子船长 …
https://www.cnblogs.com/zl1991/p/9409462.html

浅谈Android系统编译apk后so文件在dlopen时出现linker权限问题 - CSDN
https://blog.csdn.net/yang542397/article/details/88103951

Android添加自定义公共so库| 码农家园
https://www.codenong.com/cs106357975/

Android Native禁止使用系统私有库详解-阿里云开发者社区
https://developer.aliyun.com/article/748570

Android : 供應商原生開發套件 (VNDK) - sheldon_blogs - 開發者的網上家園
https://www.cnblogs.com/blogs-of-lxl/p/11232754.html

https://developer.android.com/about/versions/nougat/android-7.0-changes.html#ndk
根據官方文檔顯示,android-7.0 開始, 你再也不能使用 dlopen 開啟 system libraries,只有官方的白名單內才能,

hidl_xiaolli的专栏-CSDN博客
https://blog.csdn.net/xiaolli/article/details/79449117

java - library is not accessible for the namespace “classloader-namespace” - Stack Overflow
https://stackoverflow.com/questions/59608865/library-is-not-accessible-for-the-namespace-classloader-namespace
Modify your Android ROM so that those libraries are considered public. This can be done by adding those libraries to /system/etc/public.libraries.txt.

相關參考
AndroidQ 打通應用層到HAL層—(HIDL服務實現)_qq_34211365的博客-CSDN博客
https://blog.csdn.net/qq_34211365/article/details/105556842
Android L開始 APK 64bit 32bit 運行環境原理及決定運行環境的規則_個人文章 - SegmentFault 思否
https://segmentfault.com/a/1190000014161183