転職を繰り返したサラリーマンの多趣味ブログ

30才未経験でSEに転職した人の多趣味ブログ

【技術書メモ】配列とList<T>の操作まとめ

普段めちゃめちゃよく使う、配列とList。これは自分だけかも知れないが、普段の仕事で書くコードにあまり配列を使わない印象がある。Listの使用率が圧倒的に多い。
けど、配列が使えないと困る部分はあるので、一緒にまとめていく。

配列あるいはListに同じ値を設定する

あまり使用頻度が少なそうだが、同じ値の要素をもったリスト、配列の作り方。

// -1が20個あるリスト
var numbers = Enumerable.Repeat(-1, 20).ToList();

// -1が20個ある配列
var numbers = Enumerable.Repeat(-1, 20).ToArray();

ちなみに、-1を20個要素にもったリストを作ろうとすると、以下のように書く。
うん、これはだるい。

var numbers = new List<int> {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, };

配列あるいはListに連続した値を設定する

ここからのやつは、かなり出番がありそう。

// 1から20まで連続した値をもったリスト
var list = Enumerable.Range(1, 20).ToList();

// 1から20まで連続した値をもった配列
var array = Enumerable.Range(1, 20).ToArray();

平均値を求める

こっから、よく使うやつたちです。

var numbers = new List<int> {1, 2, 3, 4, 5, };
var average = numbers.Average();

合計を求める

var sum = numbers.Sum();

最小値、最大値を得る

var min = numbers.Min();
var max = numbers.Max();

条件に一致する要素をカウントする

var count = numbers.Count(n => n == 0);

条件に一致する要素があるか調べる

bool exists = numbers.Any(n => n % 7 == 0);

すべての要素が条件を満たしているか調べる

bool isAllPositive = numbers.All(n => n > 0);

2つのコレクション(リストや配列など)の要素が等しいか調べる

bool equal = numbers1.SequenceEqual(numbers2);

条件に一致する最初 / 最後の要素を取得する

var text = "The quick brown fox jumps over the lazy dog";
var words = text.Split(' ');

// 文字列overが取り出される
var word = words.FirstOrDefault(x => x.Length == 4);

// 文字列lazyが取り出される
var word = words.LastOrDefault(x => x.Length == 4);

条件に一致する最初 / 最後のインデックスを求める

var numbers = new List<int> { 9, 7, -5, -4, 2, 5, 4, 0, -4, };
// 戻り値は2
var firstIndex = numbers.FindIndex(n => n < 0);
// 戻り値は8
var lastIndex = numbers.FindLastIndex(n => n < 0);

条件を満たしている間だけ要素を取り出す

これはちょっとつまづいたので、説明を入れる。TakeWhileメソッドを使えば、引数に与えた条件を満たしている間の要素を取り出せる。しかし、先頭から順番に条件に当てはまるか調べるが、先頭がすでに条件から外れていたら、その時点で処理をストップする。だから、以下コードのようになる。

var numbers = new List<int> { 9, 7, -5, -4, 2, 5, 4, 0, -4, };
// 9, 7を取り出す
var selected = numbers.TakeWhile(x => x > 0);

// 何も取り出さない
var selected = numbers.TakeWhile(x => x < 0);

条件を満たしている間は要素を読み飛ばす

今度は、条件を満たしている間は要素を読み飛ばす。ただ、先頭が条件に合わないと処理がストップする動きは同じ。

var numbers = new List<int> { 9, 7, -5, -4, 2, 5, 4, 0, -4, };
// -5, -4, 2, 5, 4, 0, -4を取り出す
var selected = numbers.SkipWhile(x => x > 0);

// 9, 7, -5, -4, 2, 5, 4, 0, -4を取り出す
var selected = numbers.SkipWhile(x => x < 0);

リストの重複を排除する

var numbers = new List<int> { 9, 7, -5, -4, 2, 5, 4, 0, -4, };
var result = numbers.Distinct();

コレクションを並び替える

この並び替えは、めちゃめちゃ使うと思う。かなり重要。

// 昇順にソート
var numbers = new List<int> { 9, 7, -5, -4, 2, 5, 4, 0, -4, };
var selected = numbers.OrderBy(x => x).ToList();
selected.ForEach(Console.WriteLine);

// 降順にソート
var selected = numbers.OrderByDescending(x => x);

2つのコレクションを連結する

var numbers1 = new List<int> { 9, 7, -5, -4, 2, 5, 4, 0, -4, };
var numbers2 = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, };

var all = numbers1.Concat(numbers2).ToList();
all.ForEach(Console.WriteLine);

ここに書いたものが、すっと出てくるようになれば競プロもだいぶ解けるようになるんじゃないかと思う。反復あるのみですね。
配列とList、完璧に理解した。

【技術書メモ】文字列の操作まとめ

Atcoderなんかのような競技プログラミングをやっていると、必ず出てくるのが文字列の操作。文字列の中からある文字列を削除したり、くっつけたりと、そういった類の問題が出てくる印象がある。
で、ここらへんはすでにメソッドが用意されているので、知っていると知っていないでは、問題の解くスピードが変わってくる。けどね、全部を覚えるのは不可能です。じゃあ、どうしたらいいか考えた結果、メソッド自体を覚えるのではなく、「文字列の比較で、大文字と小文字の区別なく比較できるメソッドあったな」みたいに、こんなことができるメソッドがあったなということを覚えておけばいい感じだと思う。
で、これらを覚えておくには、ソースを書いて、そのメソッドを使ってみないとダメだ。ということで、以下つらつらと書いていきます。

文字列どうしの比較

var str1 = "ABC";
var str2 = "ABC";

if(str1 == str2) 
    Console.WriteLine("OK");

一番シンプルなやつ。演算子が==なので、直感的でわかりやすい。

大文字 / 小文字の区別なく比較する

var str1 = "windows";
var str2 = "WINDOWS";

if(String.Compare(str1, str2, ignoreCase:true) == 0) {

    Console.WriteLine("等しい");

} else {

    Console.WriteLine("等しくない");

}

String.Compareを使えば、文字列比較の幅が一気に広がる。
これより以下、String.Compareを使った文字列比較の例。

ひらがな / カタカナの区別なく比較する

var str1 = "カステラ";
var str2 = "かすてら";

// CultureInfoクラスは、言語、国、地域、暦などを表すクラス
var cultureInfo = new CultureInfo("ja-JP");
if(String.Compare(str1, str2, cultureInfo, CompareOptions.IgnoreKanaType) == 0) {

    Console.WriteLine("等しい");

} else {

    Console.WriteLine("等しくない");

}

全角 / 半角の区別なく比較する

var str1 = "HTML5";
var str2 = "HTML5;

// CultureInfoクラスは、言語、国、地域、暦などを表すクラス
var cultureInfo = new CultureInfo("ja-JP");
if(String.Compare(str1, str2, cultureInfo, CompareOptions.IgnoreWidth) == 0) {

    Console.WriteLine("等しい");

} else {

    Console.WriteLine("等しくない");

}

ここまでString.Compareメソッドを使った、文字列比較をまとめてきた。次は、文字列の判定についてまとめてみる。ここで出てくる、「指定した部分文字列で始まっているか」などは、競プロでほんとよく出てくる。

nullあるいは空文字列かを調べる

var str = "";

if (String.IsNullOrEmpty(str))
    Console.WriteLine("NG");

文字列のNULLと空文字チェックだが、自分が何も考えずに書くと以下のようになってしまう。

var str = "";

if (str == null || str == "")
    Console.WriteLine("NG");

こっちでも動くけど、IsNullOrEmptyメソッド使った方が分かりやすいし、確実だな。if文の条件は、バグポイントなので。
ちなみに、空白文字列まで調べられるメソッドもある。

if (String.IsNullOrWhiteSpace(str))

指定した部分文字列で始まっているか調べる

var str = "Visual Studio";

if (str.StartsWith("Visual"))
    Console.WriteLine("OK");

指定した部分文字列で終わっているか調べる

始まりがあれば終わりもあるということで、終わりを調べるメソッドもある。

if (str.EndsWith("Visual"))

指定した部分文字列が含まれているか調べる

始まりと終わりときて次は、そもそも場所関係なく部分文字列が含まれているかどうかを調べるときには、Containsメソッドを使う。

if (str.Contains("Program"))

条件を満たしている文字が含まれているか調べる

Anyメソッドの引数の条件に合う文字があれば、trueを返す。

var target = "C# Programming";
var isExists = target.Any(c => Char.IsLower(c));

すべての文字がある条件を満たしているか調べる

さきほどは、一つでも条件を満たした文字があるか調べるものだったが、今度はすべての文字が条件を満たしているか調べる。以下のコードだと、target変数の文字が、すべて数字だったら、trueを返す。

var target = "141421356";
var isAllDigits = target.All(c => Char.IsDigit(c));

部分文字列を検索し、その位置を求める

これも、競プロでよく使うイメージがある。先頭を0から数えた、インデックスを返す。

var target = "C# Programming";
var index = target.IndexOf("Programming");

文字列の一部を取り出す

SubStringメソッドを使えば、開始位置と長さを指定することで、任意の文字列を取り出せる。

var target = "C# Programming";
// 文字列"Pr"を取り出す
var value = target.Substring(3, 2);

ちなみに、Substringの第二引数に何も指定しなければ、文字列の最後まで取り出す。

var target = "C# Programming";
// 文字列"Programming"を取り出す
var value = target.Substring(3);

残り、ちょっと一気に書く。

文字列の前後の空白を取り除く

var target = " C# Programming ";
var replaced = target.Trim();

指定した位置から任意の数の文字を削除

var target = "01234ABC567";
// 開始位置と長さを指定
var result = target.Remove(5, 3);

文字列に別の文字列を挿入する

var target = "01234";
// 01abc234を返す
var result = target.Insert(2, "abc");

文字列の一部を別の文字列で置き換える

var target = "I hope you";
var replaced = target.Replace("hope", "wish");

小文字⇆大文字の変換

var replaced = target.ToUpper();
var replaced = target.ToLower();

指定した区切り文字で文字列配列を連結

var languages = new [] {"C#", "Java", "VB", "Ruby", };
var separator = ",";
// 文字列"C", Java, VB, Ruby"を返す
var result = String.Join(separator, languages);

文字列から文字を1つずつ取り出す

var str = "C"プログラミング";
foreach (var c in str)
    Console.Write("{0}", c);

文字配列から文字列を生成

var chars = new char[] {'P', 'r', 'o', 'g', 'r', 'a', 'm' };
var str = new string(chars);

【技術書メモ】C#においてのプロパティ書き方まとめ

Javaでプログラムを書いていたころ、プロパティは以下のように書いていた。ゲッター、セッターだ。

private string name;

public string SetName(string _name) {
    name = _name;
}

public string GetName() {
    return name;
}

けど、C#ではこんな書き方ができる。

public string Name { get; set; } = 6;

この一行で、変数Nameの初期値は6で設定し、呼び出しもできる。ただ、外部から値をセットできると色々まずいので、読み取り専用プロパティの書き方がある。

// アクセスレベルがprivate
public string GevenName { get; private set; }

// getアクセサーのみ
public string Name => FamilyName + " " + GivenName;

よし、プロパティ完璧に理解した。

条件演算子、null合体演算子まとめ

よくif文使いがちだが、if文は簡単だし、分かりやすい反面、たしかに行数は多くなる。

var list = new List<int> { 1, 2, 3, 4, 5, };
var key = 2;
int num;

if (list.Contains(key)) {
    num = 1;
else 
    num = 2;

リストに2が含まれていたら変数numに1を、リストに2が含まれていなければ変数numに2を代入するコードを書くだけで、7行も必要になる。
けど、条件演算子を支えばもっと楽に書けるよというものである。

var nums = new List<int> { 1, 2, 3, 4, 5 };
var key = 2;
var num = nums.Contains(key) ? 1 : 2;

条件演算子を使えば、3行で書けた。けど、慣れないとこの条件演算子の書式がかなりややこしい。。上の式でいうと、trueなら1、falseなら2を返している。

続いて、null合体演算子だ。
ヌルポを防ぐコードだと、一般的にはこう書くと思う。

var message = GetMessage();
if (message == null)
    message = "Default";

そう、if文で変数messageがnullかどうか、チェックしている。これも、null合体演算子を使えば楽に書ける。

var message = GetMessage() ?? "Default";

上のコードだと、GetMessage()がnullなら、??以降に書かれた戻り値を変数messageに代入する。
nullかどうか判断するコードで、null条件演算子というのもある。
これは、プロパティを持つオブジェクトのnullチェックで効力を発揮する。

return sale?.Product;

sale変数がnullの場合はnullを戻り値として返すが、sale変数がnullではない場合、sale.Productプロパティを返すというもの。

どれも、たしかに簡単に書けるけど、いざ書こうとすると多分if文で書いちゃうんだろうな。。条件演算子とnull合体演算子、完璧に理解した。

【技術書メモ】LINQ to Objectsまとめ

C#の特徴でもあるLINQ to Objects。自分の中では、C#SQLの構文が使えるイメージでいる。それは、LINQに用意されているメソッドが、「Where」、「Select」などクエリ演算子と呼ぶからだ。

var list = new List<string> {
                "Tyokyo", "New Delhi", "Bangkok", "London", "Paris", "Berlin", "Canberra", "Honkong"
};

// 文字列の長さが5以上の要素を抽出
IEnumerable<string> query = list.Where(s => s.Length <= 5);

このコードを見ると、Listで用意されているFindAllメソッドと同じ結果が得られる。

List<string> names = list.FindAll(s => s.Length <= 5);

どちらも簡単な書式だし、ラムダ式を使っているし、わざわざLINGを使うメリットって何なのかというと、ここで使ったWhereメソッドはIEnuberableインタフェースを実装している型ならば、どんなものにも使用できるという点。

// 配列でも使用できる
var array = new string[] {
                "Tyokyo", "New Delhi", "Bangkok", "London", "Paris", "Berlin", "Canberra", "Honkong"
            };

IEnumerable<string> query = array.Where(s => s.Length <= 5);

反対に、FindAllクラスはListでしか使用できない。

var list = new string[] {
                "Tyokyo", "New Delhi", "Bangkok", "London", "Paris", "Berlin", "Canberra", "Honkong"
};

// コンパイルエラーになる
var names = list.FindAll(s => s.Length <= 5);

型によって、メソッドを変えるのが面倒なので、LINQを使った方が便利。また、Whereメソッドの戻り値がIEnumerable型なので、こんな書き方もできる。

var array = new string[] {
                "Tyokyo", "New Delhi", "Bangkok", "London", "Paris", "Berlin", "Canberra", "Honkong"
            };


 // 元々はArray型だったものを、List型にキャストしている
List<string> query = (List<string>)array.Where(s => s.Length <= 5);

インタフェースでやりとりできると、色々便利だ。
LINQのメリットはこれだけじゃないと思うけど、自分の中の理解としてはこんな感じ。
ということで、LINQ to Objects完璧に理解した。

【技術書メモ】C#ラムダ式まとめ

何度も勉強しているが、すぐに忘れて使えなくなるのがラムダ式。ということで、何度も何度も勉強し直しています。
正直に言うと、「ラムダ式とは何ですか?」と聞かれてもうまく説明できる自身がない。自分の中の理解としては、ラムダ式はPredicateデリゲート型に変換できるため、Predicateデリゲート型を引数にもつ匿名メソッドに使用できる。
よって、引数に様々な条件を簡単な記述で渡せれるというのが、自分の中でのラムダ式というイメージ。

// Predicateデリゲート型変数matchに、ラムダ式を代入
Predicate<string> match =
    (string s) => {
        if (s[0] == 'A')
            return true;
        else
            return false;
    };

// 上で定義したPredicateデリゲート型変数matchを、Exixtsメソッドに代入
Console.WriteLine(list.Exists(match));

これが、Predicateデリゲート型を引数に持つメソッドに、ラムダ式を使った変数を渡しているコードだ。
けど、これじゃあ書き方が助長なので、簡素化したものがこちら。

Console.WriteLine(list.Exists(s => s[0] == 'A'));

さっきのコードと同じ結果が得られるから、こっちの書き方の方が簡単。けど、慣れないとこのコードが読めない。
自分は、=>の右側に条件を記載するものとして覚えた。=>の左側は、ListのT型がくるものと認識している。だから、Listであればint型の値がくるし、Listであればstring型の値がくる。
こんなざっくり理解でも、一応ラムダ式使えているのでOKとする。ラムダ式、完璧に理解した。

C#を勉強する16_その他の文字列操作

文字配列から文字列を生成する

// 配列の生成
var chars = new char[] { 'P', 'r', 'o', 'g', 'r', 'a', 'm', };
// 文字配列から文字列の生成
var str = new string(chars);

数値を文字列に変換する

C#では、数値を文字列に変換する方法が、「ToStringメソッド」と「String.Formatメソッド」の2通りある。しかし、ToStringメソッドには色々制限があるため、基本的にはString.Formatメソッドを使うのがよい。

int number = 12345;
// 文字列変換
Console.WriteLine(string.Format("{0}", number));

指定した書式で文字列を整形する

この場合も、string.Formatメソッドを使う。

string familyName = "yamada";
string lastName = "taro";

Console.WriteLine("FamilyaName={0}; LastName={1}", familyName, lastName);