C++による関数型プログラミング

関数型プログラミングでは、変数に関数を代入したり、関数の引数や戻り値を関数にすることができます。
C++ では、C++11 で “ラムダ式(関数リテラル)” や “std::function” が導入されました。

functional.cpp

#include <functional>
#include <iostream>

auto add1(int x, int y) -> int {
  return x + y;
}

auto add2 = [](int x, int y) -> int {return x + y;};
//std::function<int(int, int)> add2 = [](int x, int y) -> int {return x + y;};

auto add3(int x) -> std::function<int(int)> {
  return [x](int y) -> int {return x + y;};
}

auto apply(std::function<int(int, int)> f, int x, int y) -> int {
  return f(x, y);
}

auto main() -> int {
  std::cout << add1(1, 1) << std::endl;
  std::cout << add2(1, 1) << std::endl;
  std::cout << add3(1)(1) << std::endl;
  std::cout << apply(add1, 1, 1) << std::endl;
  std::cout << apply(add2, 1, 1) << std::endl;
}


参考サイト

1.Google:C++ 関数型プログラミング
2.高階関数とラムダ式

広告

C++におけるコンテナクラス

vectorはC++版の可変長配列です。

vector.cpp

#include <iostream>
#include <vector>

auto main() -> int {
  std::vector<int> vector(10, 0);

  vector[0] = 1;
  std::cout << vector[0] << std::endl;
  std::cout << vector.at(0) << std::endl;

  //range-based for loop
  for (auto& v : vector) {
    std::cout << v << std::endl;
  }

  std::vector<int> v;

  for (int i = 0; i < 10; ++i) {
    v.push_back(i);
    std::cout << v[i] << std::endl;
  }

  v.insert(v.begin(), 10);
  v.erase(v.begin(), v.begin() + 5);
  v.pop_back();

  for (auto iterator = v.begin(); iterator != v.end(); ++iterator) {
    std::cout << *iterator << std::endl;
  }
}


参考サイト

1.C++ コンテナ クラス入門
2.C++ 動的配列クラス std::vector 入門
3.range-based for loopsの要素の型について
4.C++:そういえば auto の落とし穴を示しておくと

C++による正規表現

備考)正規表現の中の丸括弧()で囲まれた部分に一致する文字列をサブマッチ文字列(submatch string)と呼びます。

regex.cpp

#include <iostream>
#include <regex>

auto main() -> int {
  //test full match
  std::cout << std::regex_match("abcde", std::regex("abc")) << std::endl; // -> 0

  //test partial match
  std::cout << std::regex_search("abcde", std::regex("abc")) << std::endl; // -> 1

  //replace the first match
  std::cout << std::regex_replace("(1+2),(3+4),(5+6)", std::regex("\\(([0-9]+)\\+([0-9]+)\\)"), "$2*$1", std::regex_constants::format_first_only) << std::endl; // -> 2*1,(3+4),(5+6)

  //replace all the matches
  std::cout << std::regex_replace("(1+2),(3+4),(5+6)", std::regex("\\(([0-9]+)\\+([0-9]+)\\)"), "$2*$1") << std::endl; // -> 2*1,4*3,6*5
}

smatch1.cpp

#include <iostream>
#include <regex>

auto main() -> int {
  std::string string = "*(1+2),(3+4),(5+6)";
  std::regex regex("\\(([0-9]+)\\+([0-9]+)\\)");
  std::smatch smatch;
  std::cout << std::regex_search(string, smatch, regex) << std::endl; // -> 1
  std::cout << smatch.prefix() << std::endl; // -> *
  //for (auto& s : smatch) std::cout << s << ",";
  std::cout << smatch[0] << "," << smatch[1] << "," << smatch[2] << std::endl; // -> (1+2),1,2
  std::cout << smatch.suffix() << std::endl; // -> ,(3+4),(5+6)
}

smatch2.cpp

#include <iostream>
#include <regex>

auto main() -> int {
  std::string string = "*(1+2),(3+4),(5+6)";
  std::regex regex("\\(([0-9]+)\\+([0-9]+)\\)");
  std::smatch smatch;
  while (std::regex_search(string, smatch, regex)) {
    std::cout << smatch.prefix() << std::endl;
    std::cout << smatch[0] << "," << smatch[1] << "," << smatch[2] << std::endl;
    std::cout << smatch.suffix() << std::endl;
    string = smatch.suffix();
  }
}

smatch3.cpp

#include <iostream>
#include <regex>

auto main() -> int {
  std::string string = "*(1+2),(3+4),(5+6)";
  std::regex regex("\\(([0-9]+)\\+([0-9]+)\\)");
  std::smatch smatch;
  auto begin = string.cbegin();
  auto end = string.cend();
  while (std::regex_search(begin, end, smatch, regex)) {
    std::cout << smatch.prefix() << std::endl;
    std::cout << smatch[0] << "," << smatch[1] << "," << smatch[2] << std::endl;
    std::cout << smatch.suffix() << std::endl;
    begin = smatch[0].second;
  }
}


参考サイト

1.標準C++の正規表現:<regex>
2.C++で正規表現を使用する
3.C++の正規表現ライブラリ:std::regex
4.正規表現ライブラリre2の簡単な使い方まとめ(FullMatch & PartialMatch)
5.Text Matching and Manipulation (Exact Match & Partial Match)
6.std::regex_replace
7.std::regex_replace(日本語)
8.std::match_results
9.std::match_results(日本語)
10.std::match_results::prefix
11.std::match_results::prefix(日本語)
12.std::match_results::suffix
13.std::match_results::suffix(日本語)

C++によるファイル入出力

ファイル全体を文字列に読み込んだ後、ファイルに書き込む。

file1.cpp

#include <fstream>

auto main() -> int {
  //std::ifstream ifstream("fin.txt");
  std::ifstream ifstream;
  ifstream.open("fin.txt");
  //std::string string((std::istreambuf_iterator<char>(ifstream)), std::istreambuf_iterator<char>());
  std::string string;
  string.assign((std::istreambuf_iterator<char>(ifstream)), std::istreambuf_iterator<char>());
  ifstream.close();
  //std::ofstream ofstream("fout.txt");
  std::ofstream ofstream;
  ofstream.open("fout.txt");
  ofstream << string;
  ofstream << std::flush;
  ofstream.close();
}


ファイルから一行ずつ vector<string> に読み込んだ後、ファイルに一行ずつ書き込む。

file2.cpp

#include <fstream>
#include <vector>

auto main() -> int {
  //std::ifstream ifstream("fin.txt");
  std::ifstream ifstream;
  ifstream.open("fin.txt");
  std::vector<std::string> lines;
  std::string line;
  while (std::getline(ifstream, line)) {
    lines.push_back(line);
  }
  ifstream.close();
  //std::ofstream ofstream("fout.txt");
  std::ofstream ofstream;
  ofstream.open("fout.txt");
  for (auto& line : lines) {
    ofstream << line << std::endl;
  }
  ofstream << std::flush;
  ofstream.close();
}


参考サイト

1.C++でファイル読込み パターン別まとめ
2.string型にファイルを一気読みできるstreambuf_iteratorのおおまかな仕組み
3.C++ファイルの読み込みまとめ
4.C++:ファイルの読み込み
5.Read a whole file into a string in C++
6.マニピュレータ

Swiftによる多次元配列

Swiftによる配列の作り方です。

array.swift

//var a:Array<Int> = [0, 1, 2, 3, 4]
var a:[Int] = [0, 1, 2, 3, 4]
a += [5, 6, 7, 8, 9]
a.append(10)
a.insert(0, at:2)
a.remove(at:5)
print(a[2..<5])
print(a[2...5])
print(a.count)
print(a)

copy.swift

var a:[Int] = [0, 0, 0, 0, 0]
var b:[Int] = a
print(a) // -> [0, 0, 0, 0, 0]
print(b) // -> [0, 0, 0, 0, 0]
a[0] = 1
b[1] = 1
print(a) // -> [1, 0, 0, 0, 0]
print(b) // -> [0, 1, 0, 0, 0]

続いて、Swiftによる多次元配列(multidimensional array)の作り方です。
以下のプログラムで、a1, a2, a3 は空配列(empty array)による初期化、b1, b2, b3 は要素数と初期値を指定した初期化です。

multiarray.swift

let n1 = 10
let n2 = 20
let n3 = 30


/* 1-dimensional array in Swift */

var a1 = [Int]()
var b1 = [Int](repeating:0, count:n1)
var c1 = [0, 1]
print(a1)
print(b1)
for i1 in 0..<n1 {
  print(b1[i1])
}
print(c1)
print(c1[0])


/* 2-dimensional array in Swift */

var a2 = [[Int]]()
var b2 = [[Int]](repeating:[Int](repeating:0, count:n2), count:n1)
var c2 = [[0, 1], [2, 3]]
print(a2)
print(b2)
for i1 in 0..<n1 {
  for i2 in 0..<n2 {
    print(b2[i1][i2])
  }
}
print(c2)
print(c2[0])
print(c2[0][0])


/* 3-dimensional array in Swift */

var a3 = [[[Int]]]()
var b3 = [[[Int]]](repeating:[[Int]](repeating:[Int](repeating:0, count:n3), count:n2), count:n1)
var c3 = [[[0, 1], [2, 3]], [[4, 5], [6, 7]]]
print(a3)
print(b3)
for i1 in 0..<n1 {
  for i2 in 0..<n2 {
    for i3 in 0..<n3 {
      print(b3[i1][i2][i3])
    }
  }
}
print(c3)
print(c3[0])
print(c3[0][0])
print(c3[0][0][0])

〈追記〉
“[swift]多次元配列の初期化”の記事を参考に、空配列による初期化のコードを修正しました。
ありがとうございました。<(_ _)>


参考サイト

1.IBM Swift Sandbox
2.Array – SwiftDoc.org
3.Array – Swift API Reference
4.Array reference guide for Swift
5.Create a two-dimensional array at runtime
6.Swiftでの行列計算(その1)
7.Swiftでの行列計算(その2)
8.[swift]多次元配列の初期化
9.Swift2 2次元配列への要素追加のエラー

Kotlinによる多次元配列

Kotlinによる多次元配列(multidimensional array)の作り方です。

array.kt

fun main(args:Array<String>) {
  var a:Array<Int> = Array<Int>(10, {0})
  var b:Array<Int> = Array<Int>(10, {i -> i})
  var c:Array<Int> = arrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
  for (x in a) println(x)
  for (x in b) println(x)
  for (x in c) println(x)

  var d:IntArray = IntArray(10)
  var e:IntArray = intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
  for (x in d) println(x)
  for (x in e) println(x)
}

multiarray.kt

fun main(args:Array<String>) {
  val n1 = 10
  val n2 = 20
  val n3 = 30


  /* 1-dimensional array in Kotlin */

  var a1 = Array<Int>(n1, {0})
  var b1:Array<Int> = a1
  for (i1 in 0..n1 - 1) {
    println(b1[i1])
  }

  var c1 = IntArray(n1)
  var d1:IntArray = c1
  for (i1 in 0..n1 - 1) {
    println(d1[i1])
  }


  /* 2-dimensional array in Kotlin */

  var a2 = Array(n1, {Array(n2, {0})})
  var b2:Array<Array<Int>> = a2
  for (i1 in 0..n1 - 1) {
    for (i2 in 0..n2 - 1) {
      println(b2[i1][i2])
    }
  }

  var c2 = Array(n1, {IntArray(n2)})
  var d2:Array<IntArray> = c2
  for (i1 in 0..n1 - 1) {
    for (i2 in 0..n2 - 1) {
      println(d2[i1][i2])
    }
  }


  /* 3-dimensional array in Kotlin */

  var a3 = Array(n1, {Array(n2, {Array<Int>(n3, {0})})})
  var b3:Array<Array<Array<Int>>> = a3
  for (i1 in 0..n1 - 1) {
    for (i2 in 0..n2 - 1) {
      for (i3 in 0..n3 - 1) {
        println(b3[i1][i2][i3])
      }
    }
  }

  var c3 = Array(n1, {Array(n2, {IntArray(n3)})})
  var d3:Array<Array<IntArray>> = c3
  for (i1 in 0..n1 - 1) {
    for (i2 in 0..n2 - 1) {
      for (i3 in 0..n3 - 1) {
        println(d3[i1][i2][i3])
      }
    }
  }
}


参考サイト

1.Create a two-dimensional array at runtime

Javaにおけるコレクションクラス

ArrayListはJava版の可変長配列です。

arraylist.java

import java.util.*;

class Main {
  public static void main(String... args) {
    List<String> list = new ArrayList<>();
    list.add("element1");
    list.add("element2");
    list.add("element3");
    list.add(null);
    list.add(0, "element0");

    System.out.println(list.get(0));
    System.out.println(list.get(1));
    System.out.println(list.get(2));
    System.out.println(list.get(3));

    for (String element : list) {
      System.out.println(element);
    }

    Iterator<String> i = list.iterator();
    while (i.hasNext()) {
      System.out.println(i.next());
    }

    list.remove(0);
    System.out.println(list.get(0));

    List<String> strings = Arrays.asList("string1", "string2", "string3");
    strings.add(null); // -> runtime error
    for (String string : strings) {
      System.out.println(string);
    }
  }
}

HashMapはJava版の連想配列です。

hashmap.java

import java.util.*;

class Main {
  public static void main(String... args) {
    Map<String, String> map = new HashMap<>();
    map.put("key1", "value1");
    map.put("key2", "value2");
    map.put("key3", "value3");

    System.out.println(map.get("key1"));
    System.out.println(map.get("key2"));
    System.out.println(map.get("key3"));

    for (String key : map.keySet()) {
      System.out.println(map.get(key));
    }

    map.remove("key1");
    System.out.println(map.get("key1"));
  }
}


参考サイト

1.java.util.ArrayList
2.java.util.HashMap