- 投稿日:2020-08-11T17:50:20+09:00
C# の Linq でリストの重複チェックと重複排除を実装する
経緯
リストの重複チェックや重複排除の実装をすることが個人的によくありますが、毎回毎回実装方法を忘れてしまい、そのたびに調べたり考えたりに多少の時間を使ってしまっていました。
この辺りは既に様々な方がまとめてくださっていますが、主に自分用のメモとして重複チェックの方法や重複排除の方法をまとめました。
実装
実装は Linq の GroupBy で書いてみました。
public static class EnumerableExtension { public static bool HasDuplicate<T, Tkey>(this IEnumerable<T> source, Func<T, Tkey> keySelector) => source.GroupBy(keySelector).Any(s => s.Skip(1).Any()); public static IEnumerable<T> DistinctByKey<T, Tkey>(this IEnumerable<T> source, Func<T, Tkey> keySelector) => source.GroupBy(keySelector).Select(s => s.First()); }使い方例
var collection = new List<string> { "佐藤", "佐々木", "佐藤", "澤田" }; // 重複をチェックする var result1 = collection.HasDuplicate(c => c); // 重複を除去する var result2 = collection.DistinctByKey(c => c);
- 投稿日:2020-08-11T13:53:31+09:00
C# で DynamoDB から時系列データを GSI を使って範囲指定して検索する
C# で Amazon DynamoDB に保存されている時系列データを GSI(グローバルセカンダリインデックス)を使って範囲指定して検索する方法です。
[事前準備1] データ
下記の構造のデータを保存できるよう、
[DynamoDBTable("SampleTable")] public class Sample { /// <summary>「SampleTable」テーブルのハッシュキー</summary> [DynamoDBHashKey] public string Id { get; set; } /// <summary>「SampleTable」テーブルのレンジキー</summary> [DynamoDBRangeKey] public string DateAndTime { get; set; } /// <summary>「Date-Time-index」GSI のハッシュキー</summary> [DynamoDBGlobalSecondaryIndexHashKey] public string Date { get; set; } /// <summary>「Date-Time-index」GSI のレンジキー</summary> [DynamoDBGlobalSecondaryIndexRangeKey] public string Time { get; set; } [DynamoDBProperty] public string Message { get; set; } public override string ToString() { return $"{Id} / {DateAndTime} / {Message}"; } }AWS Console から
Id
、DateAndTime
をキーにしたSampleTable
テーブルを用意します。
次に、下記のように
SaveAsync
メソッドを使って 10件のデータを作成します。// DynamoDB にアクセスするためのオブジェクトを用意 using var client = new AmazonDynamoDBClient(RegionEndpoint.APNortheast1); using var context = new DynamoDBContext(client); // 10件のデータを作成 for (var i = 0; i < 10; i++) { var now = DateTime.Now; await context.SaveAsync(new Sample { Id = $"{i % 3 + 1:D3}", DateAndTime = $"{now:yyyy-MM-dd HH:mm:ss.fff}", Date = $"{now:yyyy-MM-dd}", Time = $"{now:HH:mm:ss}", Message = $"メッセージ - {i + 1}" }); // 保存される時間をずらしたいので 500 msec 待機 await Task.Delay(500); }下記のように
ScanAsync
メソッドを使って全データを取得します。// 全データを取得 var listAll = await context.ScanAsync<Sample>(null).GetRemainingAsync(); Console.WriteLine("--- listAll"); listAll.OrderBy(n => n.DateAndTime).ToList().ForEach(Console.WriteLine);そうすると、下記のようにデータを取得できます。
--- listAll 001 / 2020-08-11 11:40:40.236 / メッセージ - 1 002 / 2020-08-11 11:40:41.224 / メッセージ - 2 003 / 2020-08-11 11:40:41.756 / メッセージ - 3 001 / 2020-08-11 11:40:42.293 / メッセージ - 4 002 / 2020-08-11 11:40:42.824 / メッセージ - 5 003 / 2020-08-11 11:40:43.355 / メッセージ - 6 001 / 2020-08-11 11:40:43.877 / メッセージ - 7 002 / 2020-08-11 11:40:44.412 / メッセージ - 8 003 / 2020-08-11 11:40:44.936 / メッセージ - 9 001 / 2020-08-11 11:40:45.458 / メッセージ - 10
[事前準備2] GSI
AWS Console からは下記のようにデータが保存されていることを確認できます。
事前準備の最後に、日時を範囲指定して検索できるよう、AWS Console から
Date
、Time
をキーにしたDate-Time-index
インデックス(GSI)を用意します。
これで準備は完了です。
[シナリオ1] Id = 001 のデータを取得したい
下記のようにハッシュキーに
001
を指定してQueryAsync()
メソッドを使ってデータを取得します。var list01 = await context.QueryAsync<Sample>("001").GetRemainingAsync(); Console.WriteLine("--- list01"); list01.OrderBy(n => n.DateAndTime).ToList().ForEach(Console.WriteLine);そうすると、下記のようにデータを取得できます。
--- list01 001 / 2020-08-11 11:40:40.236 / メッセージ - 1 001 / 2020-08-11 11:40:42.293 / メッセージ - 4 001 / 2020-08-11 11:40:43.877 / メッセージ - 7 001 / 2020-08-11 11:40:45.458 / メッセージ - 10
Id が 001 のデータのみを取得できています。
[シナリオ2] 2020-08-11 の 11:40:42~11:40:43 のデータを取得したい
下記のように GSI の名称
Date-Time-index
を指定し、ハッシュキーに2020-08-11
を指定して、レンジキーにはQueryOperator.Between
と11:40:42 - 11:40:43
を指定してQueryAsync()
メソッドを使ってデータを取得します。var list02 = await context.QueryAsync<Sample>( "2020-08-11", QueryOperator.Between, new List<object> { "11:40:42", "11:40:43" }, new DynamoDBOperationConfig { IndexName = "Date-Time-index" // 利用する GSI を指定 }).GetRemainingAsync(); Console.WriteLine("--- list02"); list02.OrderBy(n => n.DateAndTime).ToList().ForEach(Console.WriteLine);そうすると、下記のようにデータを取得できます。
--- list02 001 / 2020-08-11 11:40:42.293 / メッセージ - 4 002 / 2020-08-11 11:40:42.824 / メッセージ - 5 003 / 2020-08-11 11:40:43.355 / メッセージ - 6 001 / 2020-08-11 11:40:43.877 / メッセージ - 7
SampleTable
テーブルのハッシュキーであるId
をまたいで11:40:42 - 11:40:43
のデータのみを取得できています。さいごに
GSI を使って日時を範囲指定して検索することはできました。
ただ、コスト面の考慮や NoSQL らしい設計についてはできているかというと、、より良い方法があったら教えてください m(_ _)m