忘れかけていたソートコード
1年に上たってからの投稿です。そもそも私自身、継続して物事をやるとか、ブログを書く、言語学習をする、といったことにあまりたけていないというか、継続能力がないのかもしれません。。。
それはさておき、ideoneのコード履歴を見ていあたら、面白いものが残してあったので記事にしたいと思います。
import std.stdio; import std.algorithm; import std.string; void main() { auto arr=[1,1,4,5,1,4]; auto dirt = sort!("a<b")(arr); foreach(def;dirt) { writef("%d ", def); } writeln(""); }
。。。うーん、きたないコードですね(笑)それはさておき、忘れかけていた配列のソートについて書きたいと思います。
この場合、出力として期待されるのは次の通りです。
1 1 1 4 4 5
つまり、sort!("a<b")
の部分で指定した条件によってソート順序が変更される、ということになります。
先ほどのコードは昇順ソートでした。では降順ソートはどうすればよいのかというと、
先ほどの部分をsort!("a<b")
にしてあげれば降順ソートとなって出力がなされます。
5 4 4 1 1 1
という具合です。
スニペットの話
最近スタイルが変わってVSCを使い始めた、というのはメインのブログで書きました。
kotonoha-pcg.hatenablog.com
そこで、インテリセンスを使ってコーディングの時間を節約したいと思うのは当然の流れで(※自分比)、これをやる方法とかどうやって書くのかな、というのをマストドンやりながら探していました。
結論
結論からいうと、次の様な書き方になります。
import std.stdio; //d.jsonにこう記述 /* "for rep":{ "prefix": "REP", "body": [ "for(int $1=0;$1<$2;$1++){", "//nothing", "}" ], "description": "REP macro fo for-sentence" } */ REP//ここでTabまたはC-Space for(int i=0;i<n;i++){ //nothing } //っていう感じで出る
まず、Alt-F→P→スニペットでDを選択します。適当な所にcode-dなどのサンプルを参考にして書き、最後に保存します。さて、どこで迷ったのか。
動的配列のスライシング
動的配列のスライシング。TDPL p.95。1年以上間が経ってるけれど、色々あってdlang書くのをやめていて、JavaをやったりC++をやってたりしてた。で、カビかけたTDPLと蟻本を見てまたやり始めてる、という次第。
スライシング
配列中から一部の連続した領域を選択し、そこだけを操作できるようにする。TDPLのコードとはforを使って配列に代入しているのが違うくらいか。
import std.stdio, std.array, std.string; int main(){ //test of dynamic array and Associative array. auto array =new int[10]; for(int i=0; i<10; i++) { array[i]=i; } //後ろ半分だけ表示 //$はarray.lengthを表していると思われるし、 //するとこれは~.length/2~~.lengthまでの //arrayの中身を表示する、という所か。 writeln(array[$ / 2 .. $]); /* for(int i=0; i<10; i++) { writeln(array[i]); } */ return 0; }
実行結果
[5, 6, 7, 8, 9]
これ書いてるときに初めて知ったんですが、連想配列って"Associative array"なんですねぇ。今までlistedとか付けたらそれっぽいな、という感じで書いてた。なお、連想配列のコードは書いていませんが、その時点でのコードは大体ブログに乗っけるつもりでいるので、ファイル自体は後々使いまわす予定で書いています。
下のforは一応デバッグに書いたものだったけど、わざわざこの程度でassert書くのも気が引けるのでこうした。どこいってもprint系デバッグは小規模なら確実なんじゃないかなぁ、とも思ってしまう。
基本的には
writeln(array[$ .. $]);
//スライシングの式自体
[$ .. $]
のような感じで、$はarray.lengthと似ているというか、この時点では同義なものだと認識してる。一応"スライスの限界を示す、単純な添字によるアクセスのときと同様にスライスされる配列の長さを表す"、とは書いてあるので、認識的には間違ってないんじゃないかなー、という所。
後々型引数とかの方でも目にするし、今の内にもう一回読み直してもいいかもしれない、と思っていて、それで4章はまた読み直している。3章でのwith,mixin,scope他のC++では俺は見かけなかったような文は後の章で出てくるものもあるし、概要として把握しておけばいいと割り切って読み進めている。
文字列分割
文字列の分割.文字列型変数があって,そこに文字列が代入されていて,それを分割する.空白ごとに分割される.
S[] split(S)(S s); s[] を単語の配列へ分割します。 空白文字を区切りとして使います。
import std.stdio; int main(){ string str="ab cd ef 123"; string[] diff=split(str); writeln(diff[0]); return 0; }
実行結果
ab
dlang@AOJ0000
めちゃくちゃ短くてびっくりしてる.コード長103Byte.
import std.stdio; int main(){foreach(i;1..10) foreach(j;1..10) writefln("%dx%d=%d",i,j,i*j); return 0;}
D言語3(配列1,Range)
std.arrayを用いない,至って普通の配列
import std.stdio; int main() { int[] arr=[100,200,300]; for(uint i;i<arr.length;i++) writeln(arr[i]); return 0; }
出力結果
100 200 300
Rangeについて
前回の記事でも書いたD言語基礎文法最速マスターでも出てきているRangeがいまいち分からない.D言語友の会というサイトには
レンジは一般にコンテナと呼ばれる、内部に複数のデータを保有するようなオブジェクトが、特定のメンバ関数やプロパティを実装することで統一的に操作できる仕組みを提供します。
http://dusers.dip.jp/modules/wiki/?Other%2FRange%E3%81%BE%E3%81%A8%E3%82%81
と書いてある.コンテナというと直ぐC/C++のSTLにあるalgorithmを思い出すのだけれど,ある意味でそう考えて良いのかもしれない.前述したD言語基礎文法最速マスターには,4. 配列 の 配列の操作 に,
と書いてあるし,本質は理解しきれていない.昔(2年前)Cを習ったときに見た //おまじない みたいなもの,という認識になっている.
では本題に.なぜここでRangeかというと,std.arrayを用いることでRangeを利用することができる,らしい.少し読んでみると,".front"とか".popFront()"とか,どっかで見たような挙動をしている.これらの命令文の一部(insertとか)にRangeが使われているからさっきの文を読んでいた.
import std.stdio; import std.array; int main() { ///型推測でint型配列を宣言 auto arr =[1,2,3]; ///aに対し,arrの最初の要素を代入 auto a = arr.front; ///aを出力 writeln(a); ///arrの最初の要素を排除 arr.popFront(); ///bに対してarrの末尾を取得 auto b = arr.back; bを出力 writeln(b); ///arrの末尾を削除 arr.popBack(); arrの末尾に要素を追加 arr ~= 4; return 0; }
出力結果
1 3
D言語2(for/foreach)
for文書きます.基本的な構文はやっぱり変わらずC/C++と同じです.
import std.stdio; int main() { int a=1; for(uint i; i<5; i++){ writeln(a++); } return 0; }
実行結果
1 2 3 4 5
foreach文.配列ですべての要素に対して処理をすることが出来るらしい.C/C++には無い(はず)ので慣れるまで時間かかりそう.
import std.stdio; int main() { int num[5]; int n=10; for(uint i;i<5;i++){ num[i]=n+i; } foreach(val;num){ writeln(val); } return 0; }
実行結果
10 11 12 13 14